Chunker
Text and Markdown split into chunks by characters or OpenAI tokens, with overlap, cut at headings, paragraphs and sentences, for embeddings and LLM prompts.
Version 1.0.0 · 3 functions · 2 crates
Functions
What use chunker.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use chunk_text, chunk_markdown from chunker (Quillo 0.6).
chunk_text(text: str, max_chars: int, overlap: int) → listor an errortext in chunks of at most max_chars characters, each starting with the last overlap characters or so of the one before (0 for none), cut at the largest boundary that fits: blank lines, then line breaks, sentences, words. Spaces at the ends are trimmed.
chunk_markdown(text: str, max_chars: int, overlap: int) → listor an errorMarkdown in chunks of at most max_chars characters, cut at headings first, then blocks (lists, code, paragraphs), sentences and words, so a chunk is about one thing.
chunk_tokens(text: str, max_tokens: int, overlap: int, markdown: bool) → listor an errorAs chunk_markdown (or chunk_text when markdown is false), sized in OpenAI tokens (cl100k, as text-embedding-3 counts them) rather than characters: max_tokens per chunk, overlap tokens shared.
Get it
$ quillo install chunker # chunker.qwer into this folder$ quillo install chunker --example # and its example, chunker.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/chunker.qwer$ curl -O https://quillolang.org/plugins/files/chunker.qwe$ curl -O https://quillolang.org/plugins/files/chunker_sample.mdThen, in your program, all of it or only what you call:
use chunker.qweruse chunk_text, chunk_markdown from chunker // Quillo 0.6: only theseIt uses these crates, which cargo fetches the first time the plugin is built:
text-splitter = { version = "0.33", features = ["markdown", "tiktoken-rs"] }tiktoken-rs = "0.12"Example
// A help article split into chunks for an embeddings index: by headings, with a little overlap.//// quillo run chunker.qwe then open http://localhost:8080/chunksuse "chunker.qwer"let guide = read_file("chunker_sample.md")?route GET /chunks ? { size: int = 300, overlap: int = 0 } = chunk_markdown(guide, size, overlap)? | map((c) => { chars: len(c), text: c })route GET /tokens = chunk_tokens(guide, 80, 10, true)? | map((c) => { start: slice(c, 0, 40) })route GET /text = chunk_text("One sentence here. Another sentence there. And a third one to finish.", 40, 0)?$ quillo run chunker.qwe$ curl 'localhost:8080/chunks'$ curl 'localhost:8080/text'$ curl 'localhost:8080/tokens'Source
//! Text and Markdown split into chunks of a given size, with overlap, for embeddings, vector search and LLM prompts: splits fall between sections, paragraphs and sentences before words.//! version: 1.0.0//!//! [dependencies]//! text-splitter = { version = "0.33", features = ["markdown", "tiktoken-rs"] }//! tiktoken-rs = "0.12"use text_splitter::{ChunkConfig, MarkdownSplitter, TextSplitter};const MAX: usize = 20_000_000;fn sizes(text: &str, size: i64, overlap: i64) -> Result<(usize, usize), String> { if text.len() > MAX { return Err("text up to 20 MB".into()); } if size < 1 { return Err("size is at least 1".into()); } if overlap < 0 || overlap >= size { return Err("overlap is from 0 to less than the size".into()); } Ok((size as usize, overlap as usize))}/// `text` in chunks of at most `max_chars` characters, each starting with the last `overlap` characters or so of the one before (0 for none), cut at the largest boundary that fits: blank lines, then line breaks, sentences, words. Spaces at the ends are trimmed.pub fn chunk_text(text: &str, max_chars: i64, overlap: i64) -> Result<Vec<String>, String> { let (s, o) = sizes(text, max_chars, overlap)?; let cfg = ChunkConfig::new(s).with_overlap(o).map_err(|e| e.to_string())?; Ok(TextSplitter::new(cfg).chunks(text).map(String::from).collect())}/// Markdown in chunks of at most `max_chars` characters, cut at headings first, then blocks (lists, code, paragraphs), sentences and words, so a chunk is about one thing.pub fn chunk_markdown(text: &str, max_chars: i64, overlap: i64) -> Result<Vec<String>, String> { let (s, o) = sizes(text, max_chars, overlap)?; let cfg = ChunkConfig::new(s).with_overlap(o).map_err(|e| e.to_string())?; Ok(MarkdownSplitter::new(cfg).chunks(text).map(String::from).collect())}/// As `chunk_markdown` (or `chunk_text` when `markdown` is false), sized in OpenAI tokens (cl100k, as text-embedding-3 counts them) rather than characters: `max_tokens` per chunk, `overlap` tokens shared.pub fn chunk_tokens(text: &str, max_tokens: i64, overlap: i64, markdown: bool) -> Result<Vec<String>, String> { let (s, o) = sizes(text, max_tokens, overlap)?; let bpe = tiktoken_rs::cl100k_base_singleton(); let cfg = ChunkConfig::new(s).with_sizer(bpe).with_overlap(o).map_err(|e| e.to_string())?; Ok(if markdown { MarkdownSplitter::new(cfg).chunks(text).map(String::from).collect() } else { TextSplitter::new(cfg).chunks(text).map(String::from).collect() })}Related
html_markdown.qwer · 1.0.0HTML turned into clean Markdown as Turndown does: headings, lists, links, images, code blocks, quotes and tables kept, scripts and the parts you name dropped; for importing old posts, editor output, and pages for an LLM.7 views · 6 downloadsTokens tokens.qwer · 1.0.0Text counted, cut and split in OpenAI model tokens, to keep prompts inside a model's window and estimate their cost; Claude counts tokens its own way, so this is for OpenAI models only.7 views · 7 downloadsVector search vectors.qwer · 1.0.0Nearest neighbours among embeddings, by collection: "more like this" and semantic search by cosine similarity, saved to a file and loaded back.5 views · 8 downloadsGoogle Gemini gemini.qwer · 1.0.0Google's Gemini API with no SDK: generateContent with a system instruction and function calls, streams collected, embedContent and batches of it, token counts, a blocked prompt told apart from a stop for safety, and 429s retried after the delay the error names.3 views · 9 downloadsOllama ollama.qwer · 1.0.0A model on your own machine through Ollama: generate and chat with their streams collected and timings turned into tokens per second, tool calls, JSON output, embeddings, what is installed and loaded, pulls, and a clear word when the server is stopped or the model is missing.2 views · 8 downloadsOpenAI openai.qwer · 1.0.0Chat completions, the Responses API and embeddings from OpenAI or any server that speaks its API, chosen by OPENAI_BASE_URL: tool calls parsed and answered, streams put back together piece by piece, 429s retried as the headers say and a spent quota not retried at all.3 views · 10 downloadsThread 0 posts
On Chunker: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.