Document Summarisation
Generate a one-paragraph summary of extracted documents for search snippets, indexing, or quick reviews. Choose extractive summarization for deterministic, network-free local processing, or abstractive for fluent, AI-generated prose.
Backends
Section titled “Backends”| Strategy | Cargo feature | Network | Quality | Latency |
|---|---|---|---|---|
Extractive (default) |
summarization |
None — fully local | Sentence-level selection from source | < 100 ms typical |
Abstractive |
summarization-llm |
LLM provider | Generates novel prose, can summarise across sentences | Provider-dependent |
When to Use
Section titled “When to Use”- You need a one-paragraph TL;DR for indexing or search snippets.
- You need a deterministic, network-free summary (extractive only).
- You need a fluent abstractive summary for downstream LLM consumption.
When Not to Use
Section titled “When Not to Use”- You need full per-section summaries. Chunk the document first and summarise each chunk separately.
- You need cross-document summarisation. Summarise per document, then summarise the summaries with the LLM backend.
Configuration
Section titled “Configuration”TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
import asynciofrom xberg import extract, ExtractInput, ExtractInputKindfrom xberg._xberg import ExtractionConfig
async def main() -> None: input = ExtractInput(kind=ExtractInputKind("uri"), uri="https://example.com/text/book_war_and_peace_1p.txt") config = ExtractionConfig.from_json("{\"summarization\":{\"max_tokens\":80,\"strategy\":\"extractive\"}}") result = await extract(input, config) print(result.results[0].summary)
asyncio.run(main())TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
import { ExtractInput, ExtractInputKind, ExtractionConfig, SummaryStrategy, extract } from "@xberg-io/xberg";async function main() { const input: ExtractInput = { kind: ExtractInputKind.Uri, uri: "https://example.com/text/book_war_and_peace_1p.txt" }; const config: ExtractionConfig = { summarization: { maxTokens: 80, strategy: SummaryStrategy.Extractive } }; const result = await extract(input, config); console.log(result.results?.[0]?.summary);}
void main();TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
import { WasmExtractInput, WasmExtractInputKind, extract } from "@xberg-io/xberg-wasm";async function main() { const input: WasmExtractInput = (() => { const _u0 = WasmExtractInput.default(); _u0.kind = WasmExtractInputKind.Uri; _u0.uri = "https://example.com/text/book_war_and_peace_1p.txt"; return _u0; })(); const result = await extract(input, { summarization: { maxTokens: 80, strategy: "extractive" } }); console.log(result.results[0].summary);}
void main();TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
use xberg::extract;use xberg::ExtractInput;
#[tokio::main]async fn main() { let input_json: serde_json::Value = serde_json::from_str(r#"{"kind":"uri","uri":"https://example.com/text/book_war_and_peace_1p.txt"}"#).unwrap(); let input = serde_json::from_value::<ExtractInput>(input_json).unwrap(); let config_json: serde_json::Value = serde_json::from_str(r#"{"summarization":{"max_tokens":80,"strategy":"extractive"}}"#).unwrap(); let config = serde_json::from_value(config_json).unwrap(); let result = extract(input, &config).await.expect("call failed"); println!("{:?}", result.results[0].summary);}TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
package main
import ( "fmt" xberg "github.com/xberg-io/xberg/packages/go")
func ptr[T any](value T) *T { return &value }func main() { input := xberg.ExtractInput{ Kind: ptr(xberg.ExtractInputKindURI), URI: ptr(`https://example.com/text/book_war_and_peace_1p.txt`), } config := xberg.ExtractionConfig{ Summarization: &xberg.SummarizationConfig{ Strategy: ptr(xberg.SummaryStrategyExtractive), MaxTokens: ptr(uint32(80)), }, } result, err := xberg.Extract(input, config) if err != nil { panic(err) } fmt.Printf("%+v\n", result.Results[0].Summary)}TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
import io.xberg.*;
public final class Example { public static void main(String[] args) throws Exception { var inputJson = "{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}"; var input = JsonUtil.fromJson(inputJson, ExtractInput.class); var configJson = "{\"summarization\":{\"max_tokens\":80,\"strategy\":\"extractive\"}}"; var config = JsonUtil.fromJson(configJson, ExtractionConfig.class); var result = Xberg.extract(input, config); System.out.println(result.results().get(0).summary()); }}TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
import io.xberg.*import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
fun main() = kotlinx.coroutines.runBlocking { val mapper = jacksonObjectMapper().setPropertyNamingStrategy(com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE) val input = mapper.readValue("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}", ExtractInput::class.java) val config = mapper.readValue("{\"summarization\":{\"max_tokens\":80,\"strategy\":\"extractive\"},\"url\":{\"crawl\":{\"ssrf\":{}}}}", ExtractionConfig::class.java) val result = Xberg.extract(input, config) println(result.results.first().summary)}TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
using System;using System.Text.Json;using Xberg;
var ConfigOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };var result = await XbergConverter.ExtractAsync(new ExtractInput { Kind = JsonSerializer.Deserialize<ExtractInputKind>("\"uri\"", ConfigOptions)!, Uri = "https://example.com/text/book_war_and_peace_1p.txt" }, new ExtractionConfig { Summarization = new SummarizationConfig { MaxTokens = 80, Strategy = JsonSerializer.Deserialize<SummaryStrategy>("\"extractive\"", ConfigOptions)! } });Console.WriteLine(result.Results[0].Summary);TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
import Xberg
let result = try await Xberg.extract("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}", "{\"summarization\":{\"max_tokens\":80,\"strategy\":\"extractive\"}}")debugPrint(result.results()[0].summary() as Any)TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
require "xberg"result = Xberg.extract(Xberg::ExtractInput.new(kind: 'uri', uri: 'https://example.com/text/book_war_and_peace_1p.txt'), { 'summarization' => { 'max_tokens' => 80, 'strategy' => 'extractive' } })puts result.results[0].summary.inspectTextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Xberg\Xberg;use Xberg\ExtractInput;$input = \Xberg\ExtractInput::from_json(json_encode(["kind" => "uri", "uri" => "https://example.com/text/book_war_and_peace_1p.txt"]));$result = Xberg::extract($input, ["summarization" => ["max_tokens" => 80, "strategy" => "extractive"]]);var_dump($result->getResults()[0]->getSummary());TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
input_value = %Xberg.ExtractInput{kind: "uri", uri: "https://example.com/text/book_war_and_peace_1p.txt"}result = Xberg.extract_async(input_value, "{\"summarization\":{\"max_tokens\":80,\"strategy\":\"extractive\"}}")IO.inspect(Enum.at(result.results, 0).summary)TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
import 'dart:io';import 'package:xberg/xberg.dart';import 'package:xberg/src/xberg_bridge_generated/frb_generated.dart' show RustLib;Future<void> main() async { await RustLib.init(); try { final input = await createExtractInputFromJson(json: '{"kind":"uri","uri":"https://example.com/text/book_war_and_peace_1p.txt"}'); final config = await createExtractionConfigFromJson(json: '{"summarization":{"max_tokens":80,"strategy":"extractive"}}'); final result = await XbergBridge.extract(input, config: config); stdout.writeln(result.results[0].summary); } finally { RustLib.dispose(); }}TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
const std = @import("std");const xberg = @import("xberg");
pub fn main() !void { const _result_json = try xberg.extract("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}", "{\"summarization\":{\"max_tokens\":80,\"strategy\":\"extractive\"}}"); defer std.heap.c_allocator.free(_result_json); std.debug.print("{s}\n", .{_result_json});
}TextRank extractive summary over a multi-paragraph plain text document. Pure-Rust, deterministic, no external services required.
#include <assert.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "xberg.h"
int main(void) { XBERGAlefHandle input_handle = xberg_extract_input_from_json("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}"); XBERGAlefHandle config_handle = xberg_extraction_config_from_json("{\"summarization\":{\"max_tokens\":80,\"strategy\":\"extractive\"}}"); XBERGAlefHandle result = xberg_extract(input_handle, config_handle); xberg_extract_input_free(input_handle); xberg_extraction_config_free(config_handle); xberg_extraction_result_free(result); return EXIT_SUCCESS;}For CLI and server configuration, add the same settings to xberg.toml:
[summarization]strategy = "extractive"max_tokens = 200Abstractive Backend
Section titled “Abstractive Backend”Switch the strategy and attach an LlmConfig:
LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
import asynciofrom xberg import extract, ExtractInput, ExtractInputKindfrom xberg._xberg import ExtractionConfig
async def main() -> None: input = ExtractInput(kind=ExtractInputKind("uri"), uri="https://example.com/text/book_war_and_peace_1p.txt") config = ExtractionConfig.from_json("{\"summarization\":{\"llm\":{\"max_tokens\":200,\"model\":\"openai/gpt-4o-mini\",\"temperature\":0.0},\"max_tokens\":150,\"strategy\":\"abstractive\"}}") result = await extract(input, config) print(result.results[0].summary)
asyncio.run(main())LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
import { ExtractInput, ExtractInputKind, ExtractionConfig, SummaryStrategy, extract } from "@xberg-io/xberg";async function main() { const input: ExtractInput = { kind: ExtractInputKind.Uri, uri: "https://example.com/text/book_war_and_peace_1p.txt" }; const config: ExtractionConfig = { summarization: { llm: { maxTokens: 200, model: "openai/gpt-4o-mini", temperature: 0.0 }, maxTokens: 150, strategy: SummaryStrategy.Abstractive } }; const result = await extract(input, config); console.log(result.results?.[0]?.summary);}
void main();LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
import { WasmExtractInput, WasmExtractInputKind, extract } from "@xberg-io/xberg-wasm";async function main() { const input: WasmExtractInput = (() => { const _u0 = WasmExtractInput.default(); _u0.kind = WasmExtractInputKind.Uri; _u0.uri = "https://example.com/text/book_war_and_peace_1p.txt"; return _u0; })(); const result = await extract(input, { summarization: { llm: { maxTokens: 200, model: "openai/gpt-4o-mini", temperature: 0.0 }, maxTokens: 150, strategy: "abstractive" } }); console.log(result.results[0].summary);}
void main();LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
use xberg::extract;use xberg::ExtractInput;
#[tokio::main]async fn main() { let input_json: serde_json::Value = serde_json::from_str(r#"{"kind":"uri","uri":"https://example.com/text/book_war_and_peace_1p.txt"}"#).unwrap(); let input = serde_json::from_value::<ExtractInput>(input_json).unwrap(); let config_json: serde_json::Value = serde_json::from_str(r#"{"summarization":{"llm":{"max_tokens":200,"model":"openai/gpt-4o-mini","temperature":0.0},"max_tokens":150,"strategy":"abstractive"}}"#).unwrap(); let config = serde_json::from_value(config_json).unwrap(); let result = extract(input, &config).await.expect("call failed"); println!("{:?}", result.results[0].summary);}LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
package main
import ( "fmt" xberg "github.com/xberg-io/xberg/packages/go")
func ptr[T any](value T) *T { return &value }func main() { input := xberg.ExtractInput{ Kind: ptr(xberg.ExtractInputKindURI), URI: ptr(`https://example.com/text/book_war_and_peace_1p.txt`), } config := xberg.ExtractionConfig{ Summarization: &xberg.SummarizationConfig{ Strategy: ptr(xberg.SummaryStrategyAbstractive), MaxTokens: ptr(uint32(150)), Llm: &xberg.LlmConfig{ Model: `openai/gpt-4o-mini`, Temperature: ptr(float64(0.0)), MaxTokens: ptr(uint64(200)), }, }, } result, err := xberg.Extract(input, config) if err != nil { panic(err) } fmt.Printf("%+v\n", result.Results[0].Summary)}LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
import io.xberg.*;
public final class Example { public static void main(String[] args) throws Exception { var inputJson = "{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}"; var input = JsonUtil.fromJson(inputJson, ExtractInput.class); var configJson = "{\"summarization\":{\"llm\":{\"max_tokens\":200,\"model\":\"openai/gpt-4o-mini\",\"temperature\":0.0},\"max_tokens\":150,\"strategy\":\"abstractive\"}}"; var config = JsonUtil.fromJson(configJson, ExtractionConfig.class); var result = Xberg.extract(input, config); System.out.println(result.results().get(0).summary()); }}LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
import io.xberg.*import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
fun main() = kotlinx.coroutines.runBlocking { val mapper = jacksonObjectMapper().setPropertyNamingStrategy(com.fasterxml.jackson.databind.PropertyNamingStrategies.SNAKE_CASE) val input = mapper.readValue("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}", ExtractInput::class.java) val config = mapper.readValue("{\"summarization\":{\"llm\":{\"max_tokens\":200,\"model\":\"openai/gpt-4o-mini\",\"temperature\":0.0},\"max_tokens\":150,\"strategy\":\"abstractive\"},\"url\":{\"crawl\":{\"ssrf\":{}}}}", ExtractionConfig::class.java) val result = Xberg.extract(input, config) println(result.results.first().summary)}LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
using System;using System.Text.Json;using Xberg;
var ConfigOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };var result = await XbergConverter.ExtractAsync(new ExtractInput { Kind = JsonSerializer.Deserialize<ExtractInputKind>("\"uri\"", ConfigOptions)!, Uri = "https://example.com/text/book_war_and_peace_1p.txt" }, new ExtractionConfig { Summarization = new SummarizationConfig { Llm = new LlmConfig { MaxTokens = 200, Model = "openai/gpt-4o-mini", Temperature = 0.0d }, MaxTokens = 150, Strategy = JsonSerializer.Deserialize<SummaryStrategy>("\"abstractive\"", ConfigOptions)! } });Console.WriteLine(result.Results[0].Summary);LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
import Xberg
let result = try await Xberg.extract("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}", "{\"summarization\":{\"llm\":{\"max_tokens\":200,\"model\":\"openai/gpt-4o-mini\",\"temperature\":0.0},\"max_tokens\":150,\"strategy\":\"abstractive\"}}")debugPrint(result.results()[0].summary() as Any)LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
require "xberg"result = Xberg.extract(Xberg::ExtractInput.new(kind: 'uri', uri: 'https://example.com/text/book_war_and_peace_1p.txt'), { 'summarization' => { 'llm' => { 'max_tokens' => 200, 'model' => 'openai/gpt-4o-mini', 'temperature' => 0.0 }, 'max_tokens' => 150, 'strategy' => 'abstractive' } })puts result.results[0].summary.inspectLLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use Xberg\Xberg;use Xberg\ExtractInput;$input = \Xberg\ExtractInput::from_json(json_encode(["kind" => "uri", "uri" => "https://example.com/text/book_war_and_peace_1p.txt"]));$result = Xberg::extract($input, ["summarization" => ["llm" => ["max_tokens" => 200, "model" => "openai/gpt-4o-mini", "temperature" => 0.0], "max_tokens" => 150, "strategy" => "abstractive"]]);var_dump($result->getResults()[0]->getSummary());LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
input_value = %Xberg.ExtractInput{kind: "uri", uri: "https://example.com/text/book_war_and_peace_1p.txt"}result = Xberg.extract_async(input_value, "{\"summarization\":{\"llm\":{\"max_tokens\":200,\"model\":\"openai/gpt-4o-mini\",\"temperature\":0.0},\"max_tokens\":150,\"strategy\":\"abstractive\"}}")IO.inspect(Enum.at(result.results, 0).summary)LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
import 'dart:io';import 'package:xberg/xberg.dart';import 'package:xberg/src/xberg_bridge_generated/frb_generated.dart' show RustLib;Future<void> main() async { await RustLib.init(); try { final input = await createExtractInputFromJson(json: '{"kind":"uri","uri":"https://example.com/text/book_war_and_peace_1p.txt"}'); final config = await createExtractionConfigFromJson(json: '{"summarization":{"llm":{"max_tokens":200,"model":"openai/gpt-4o-mini","temperature":0.0},"max_tokens":150,"strategy":"abstractive"}}'); final result = await XbergBridge.extract(input, config: config); stdout.writeln(result.results[0].summary); } finally { RustLib.dispose(); }}LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
const std = @import("std");const xberg = @import("xberg");
pub fn main() !void { const _result_json = try xberg.extract("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}", "{\"summarization\":{\"llm\":{\"max_tokens\":200,\"model\":\"openai/gpt-4o-mini\",\"temperature\":0.0},\"max_tokens\":150,\"strategy\":\"abstractive\"}}"); defer std.heap.c_allocator.free(_result_json); std.debug.print("{s}\n", .{_result_json});
}LLM-driven abstractive summary. Skipped automatically when XBERG_LLM_API_KEY (or OPENAI_API_KEY) is not set.
#include <assert.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "xberg.h"
int main(void) { XBERGAlefHandle input_handle = xberg_extract_input_from_json("{\"kind\":\"uri\",\"uri\":\"https://example.com/text/book_war_and_peace_1p.txt\"}"); XBERGAlefHandle config_handle = xberg_extraction_config_from_json("{\"summarization\":{\"llm\":{\"max_tokens\":200,\"model\":\"openai/gpt-4o-mini\",\"temperature\":0.0},\"max_tokens\":150,\"strategy\":\"abstractive\"}}"); XBERGAlefHandle result = xberg_extract(input_handle, config_handle); xberg_extract_input_free(input_handle); xberg_extraction_config_free(config_handle); xberg_extraction_result_free(result); return EXIT_SUCCESS;}The model receives the extracted content and returns the summary verbatim. Token usage records in ExtractedDocument.llm_usage with source = "summarisation_abstractive".
max_tokens Semantics
Section titled “max_tokens Semantics”| Strategy | What max_tokens caps |
|---|---|
Extractive |
Loose whitespace tokens in the output summary. The TextRank selector stops appending sentences once it would exceed the cap. |
Abstractive |
A prompt hint asking the model for approximately this many tokens — not a provider hard cap. The provider’s request limit comes separately from SummarizationConfig.llm.max_tokens. |
Leave None to let the backend pick a sensible default.
Output Shape
Section titled “Output Shape”{ "summary": { "text": "The contract sets out a 3-year support agreement with quarterly billing and a fixed escalation cap of 4%.", "strategy": "extractive", "token_count": 19 }}Provider Setup (Abstractive Only)
Section titled “Provider Setup (Abstractive Only)”Pick any liter-llm provider — see LLM Integration. For most documents, gpt-4o-mini, claude-3-5-haiku, or google/gemini-2.0-flash give good cost / quality trade-offs.
API-key precedence:
SummarizationConfig.llm.api_keyXBERG_LLM_API_KEY- Per-provider env var
Related
Section titled “Related”- LLM Integration — provider matrix, API-key precedence
- Document Translation — sibling LLM post-processor
- Configuration Reference