README.md - #1
Open
Professor-Codephreak wants to merge 7 commits into
Open
Conversation
open source or go away
md-embed.py ends at Chroma, via interactive input() prompts, defaulting to
all-MiniLM-L6-v2 (384) or nomic-embed-text. RAGE runs bge-m3 at 1024 dims in
PostgreSQL with pgvectorscale/StreamingDiskANN. The pipeline
codebase --BaseGen--> markdown --md-embed--> chunks --> Chroma
therefore stopped one hop short of RAGE in three ways at once: wrong store,
wrong dimension, un-scriptable. ragesink is that hop, prompt-free so it runs
from cron.
· markdown-aware splitting — headers first, then 512-word packing (the
production chunk size). In a BaseGen doc every file is a section, so the
heading carries the path; a '#' inside a fence is a comment, not a heading.
· index selection reported, not hidden: vectorscale/DiskANN, else
pgvector/HNSW, else none — and it says which.
· idempotent WITH an orphan prune. Upsert on (doc_name, chunk_idx) never
removes anything, so a document that re-chunks shorter leaves stale rows
above the new count that similarity search still serves as current. Prunes
chunk_idx >= len(chunks), and only after a successful store: a run that
wrote nothing is no evidence about the document's shape.
Verified end to end on live Postgres + Ollama: 20 chunks in; the same document
truncated then reported 3/3 stored, pruned 17. Semantic query 'how does the
federation handle a peer that does not answer' returned federate.py first.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhsWQt3fduoCMQgG42Ddg8
OPTIMIZATION. Chunks now carry sha256(model || dims || text). Only chunks whose
hash changed are embedded, so a re-ingest over an unchanged corpus does almost
no work. Measured on 20 chunks, 4-core CPU, no GPU:
cold ingest 20/20 515.5 s
re-run unchanged 0/20 0.49 s ~1050x
one section edited 1/20 14.0 s
That is the number that decides whether ingestion can go on a timer.
The model and width are INSIDE the hash deliberately: the same text under a
different embedder is not the same vector, and silently keeping the old row is
how a table ends up with two embedding spaces mixed — a failure that yields
plausible nonsense rather than an error.
Embedding now batches 32 chunks per /api/embed call, with automatic fallback to
the older per-chunk /api/embeddings. Honest about the gain: batching cuts round
trips, but on CPU the model's forward pass is nearly all the cost, so it barely
moves the cold number. The hash is what delivers the speedup.
content_hash is added with ADD COLUMN IF NOT EXISTS, so this attaches to an
existing RAGE store with no migration; pre-existing rows have a NULL hash and
re-embed once.
The prune guard is tightened rather than loosened: it now fires when the run has
evidence about the document's shape — it either wrote something, or verified
every chunk as already-current. A run that stored nothing because the embedder
was down still deletes nothing.
TECHNICAL.md documents the whole path end to end: BaseGen's two
retrieval-hostile defaults, header-first splitting and why it matters for
attribution, the hash, the index fallback that announces itself, the upsert +
prune contract, measured costs, the schema, and a verified retrieval example.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhsWQt3fduoCMQgG42Ddg8
…ogress PACKING. Splitting emitted one chunk per markdown section regardless of size. On the mindX docs that was 440 chunks averaging 174 words against a 512 cap: 3x the embedding cost, and a corpus fragmented into pieces too small to carry their own context. Consecutive sections now pack up to chunk_words. Same corpus: 440 -> 197 chunks, 55% fewer. Oversized sections still split, and a split section repeats its heading on every piece. OWNERSHIP. Attaching to a store you do not own is normal — a shared RAGE database grants INSERT/UPDATE without table ownership, and ALTER TABLE then raises InsufficientPrivilege and aborted the entire run. ensure_schema now tries the ADD COLUMN once, guarded, and the fallback index paths no longer retry it. Without content_hash the skip optimisation is simply off and every run re-embeds: slow but correct, and it SAYS so, because a silent 100x slowdown looks exactly like a hang. BUFFERING. Python block-buffers stdout when redirected, so a multi-hour ingest printed nothing until the buffer filled — indistinguishable from a hang, and I diagnosed a live run as stalled when it was fine. Progress lines flush. Also --strip-ext, to name documents the way an existing store already does (relpath without the extension) rather than forking the convention. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhsWQt3fduoCMQgG42Ddg8
A long ingest over an SSH tunnel WILL see the tunnel flap. Two failures on the same run, both real, both now handled: 1. The tunnel died while the process kept going, so it spent ~25 s of CPU per chunk producing vectors with nowhere to store them. alive() now checks the connection BEFORE each embed batch — after is too late, the cost is already paid. 2. The connection then died BETWEEN that pre-check and the INSERT, surfacing as a raw psycopg2.OperationalError that killed the run at file 4 of 42. A pre-check alone cannot close that window, so the write path reconnects and retries the file, backing off 5/10/15/20s over RECONNECT_TRIES attempts. Files commit atomically, so retrying one is clean, and anything already committed is skipped by hash on the way back through. commit() is guarded the same way: a lost commit reconnects and the file is redone next run rather than being silently counted as stored. Verified by the resume this was written for: 3 previously-stored documents skipped in under a second, ingest continued at file 4. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhsWQt3fduoCMQgG42Ddg8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
md-embed (c) 2024 web3dguy
A Python script for processing Markdown files, generating embeddings, and storing them in a vector store. This tool allows you to clean, split, and embed Markdown documents using various methods and embedding models.
Features
Installation
Prerequisites
Python 3.7 or higher pip Git (optional, for cloning the repository)Clone the Repository
git clone https://github.com/GATERAGE/mdmbed.git cd mdmbedInstall Required Packages
Install the required Python packages using pip:
Note: The requirements.txt file should list all the dependencies, such as tqdm, langchain, chromadb, huggingface, etc.
Usage
Run the script using Python:
Command-Line Arguments
Upon running the script, you will be prompted to choose an input method:
JSON Input File
If you choose Option 1, you will be asked to provide:
The script will:
Folder of Markdown Files
If you choose Option 2, you will be asked to provide:
The script will:
Single Markdown File
If you choose Option 3, you will be asked to provide:
The script will:
Document Splitting
After loading the documents, you will be prompted to split them:
You will have the option to preview the split data before proceeding.
Embedding and Saving
After splitting, you will be prompted to embed and save the documents:
The script will:
Examples
Example 1: Process JSON Input File
Choose Input Method: 1
Proceed through the prompts to clean data, split documents, and embed them.
Example 2: Process Folder of Markdown Files with Filters Off
Choose Input Method: 2
Proceed through the prompts to load, split, and embed the documents.
Contributing
Contributions are welcome! Please follow these steps:
Make your changes and commit them:
git commit -m "Add your message"Push to the branch:
Please make sure your code adheres to the existing style and that all tests pass.
License
This project is licensed under the MIT License.
Acknowledgments
web3dguy
LangChain for text splitting and document handling.
HuggingFace for embedding models.
Chroma for the vector store.
TQDM for progress bars.
The open-source community for continuous support and contributions.
Markdown Processor and Embedder
md-embed processes markdown files, cleans and prepares the data, splits the text into manageable chunks, and creates embeddings for use in vector databases (specifically ChromaDB). It supports multiple input methods and provides options for customizing the splitting and embedding process.
Features
#,##). Allows for custom header level selection. Preserves header hierarchy in metadatalangchain_huggingface). Defaults toall-MiniLM-L6-v2langchain_community). Defaults tonomic-embed-text, requires a local Ollama server running athttp://localhost:11434langchain_chroma) to store embeddings and associated metadataloggingmoduleRequirements
langchain(various components - see import statements)chromadbtqdmbeautifulsoup4(if you were scraping, but this script doesn't actually use it)requests(if you were scraping, but this script doesn't actually use it)To install the required packages, run:
md-embed can be run from the command line. It provides a command-line interface using argparse with the following option:
--filters-off: Disables the "404" and "©" filters
The script will then guide you through a series of interactive prompts to configure the processing:
Input Method Selection: Choose between JSON input, a folder of markdown files, or a single markdown file
Input File/Folder/URL: Provide the path to the input file or folder, as appropriate
Output Folder (for JSON input): Specify the directory where cleaned markdown files will be saved
Data Cleaning Options: The script will show total entires and total duplicates
Language: Specify the primary language of the input files (e.g., "TypeScript", "Python")
Splitting Method: Choose between "markdown" (header-based splitting) and "recursive" (chunk size and overlap)
Markdown Splitting Options (if applicable):
Remove Links: Choose whether to remove markdown links
Header Levels: Specify which header levels to split on (e.g., "1,2,3" for #, ##, and ###). Enter "all" for all header levels
Recursive Splitting Options (if applicable):
Remove Links: Choose whether to remove markdown links
Chunk Size: Specify the desired chunk size (in characters)
Chunk Overlap: Specify the desired chunk overlap (in characters)
Preview Splits: Choose whether to preview the split data ("yes", "full", or "no")
Split Again: You'll be prompted to continue or modify the settings
Embedding Method: Choose between "huggingface" and "ollama"
Embedding Model (Hugging Face): Enter the Hugging Face model name (defaults to all-MiniLM-L6-v2)
Embedding Model (Ollama): Enter the Ollama model name (defaults to nomic-embed-text)
Persistence Directory: Specify the directory where the ChromaDB database will be stored
Collection Name: Choose a name for the ChromaDB collection
Example (JSON Input):
Follow the prompts, providing the necessary information (input file, output folder, embedding choices, etc.)
Example (Disabling Filters):
Cleaned Markdown Files (JSON Input): If using JSON input, the script will save cleaned markdown files to the specified output folder
ChromaDB Database: The script will create a ChromaDB database in the specified persistence directory, containing the embeddings and metadata
Logs: The logs directory will contain logs of removed files (if any) and duplicate entries (if using JSON input)
file_to_url.json: Json file that contains the original URL of each document
Error Handling
The script includes error handling for various scenarios, such as:
Invalid input file/folder paths
File I/O errors
Exceptions during data cleaning, splitting, or embedding
Invalid user input for prompts
Errors are logged using the logging module
Notes
The script assumes that the input JSON data has "url" and "markdown" keys for each entry
The script uses uuid4 to generate unique IDs for each document in the vector database
The script processes in batches to deal with a large number of splits
Disclaimer: This tool is provided "as is" without warranty of any kind. Use it at your own risk. Open source or go away.