import hashlib
import json
import math
import re
import sqlite3
from datetime import datetime, timezone
DIMENSIONS = 256
def normalize(text: str) -> str:
text = re.sub(r"\r\n?", "\n", text)
text = re.sub(r"[ \t]+", " ", text)
text = re.sub(r"\n{3,}", "\n\n", text)
return text.strip()
def chunk_markdown(markdown: str, max_words: int = 90):
chunks, heading, buffer = [], "", []
for line in normalize(markdown).splitlines():
if line.startswith("#"):
if buffer:
chunks.append((heading, "\n".join(buffer)))
buffer = []
heading = line.lstrip("# ")
else:
buffer.append(line)
if len(" ".join(buffer).split()) >= max_words:
chunks.append((heading, "\n".join(buffer)))
buffer = []
if buffer:
chunks.append((heading, "\n".join(buffer)))
return [(h, t.strip()) for h, t in chunks if t.strip()]
def embed(text: str):
vector = [0.0] * DIMENSIONS
for token in re.findall(r"[a-z0-9]+", text.lower()):
slot = int(hashlib.sha256(token.encode()).hexdigest()[:8], 16) % DIMENSIONS
vector[slot] += 1.0
length = math.sqrt(sum(x * x for x in vector)) or 1.0
return [x / length for x in vector]
def cosine(a, b):
return sum(x * y for x, y in zip(a, b))
def ingest(db, url, title, markdown):
cleaned = normalize(markdown)
page_hash = hashlib.sha256(cleaned.encode()).hexdigest()
crawled_at = datetime.now(timezone.utc).isoformat()
db.execute("DELETE FROM chunks WHERE source_url = ?", (url,))
for index, (heading, text) in enumerate(chunk_markdown(cleaned)):
embedding_text = f"{title}\n{heading}\n{text}"
db.execute(
"INSERT INTO chunks VALUES (?, ?, ?, ?, ?, ?, ?)",
(url, title, heading, index, text, json.dumps(embed(embedding_text)),
f"{page_hash}:{crawled_at}"),
)
db.commit()
def search(db, question, limit=3):
query_vector = embed(question)
rows = db.execute(
"SELECT source_url, title, heading, body, vector FROM chunks"
).fetchall()
ranked = [
(cosine(query_vector, json.loads(vector)), url, title, heading, body)
for url, title, heading, body, vector in rows
]
return sorted(ranked, reverse=True)[:limit]
db = sqlite3.connect(":memory:")
db.execute("""CREATE TABLE chunks (
source_url TEXT, title TEXT, heading TEXT, chunk_index INTEGER,
body TEXT, vector TEXT, version TEXT
)""")
sample = """# Acme Docs
## Authentication
Send an API key in the Authorization header. Never expose the key in client code.
## Retries
Retry rate limits with exponential backoff and jitter. Do not retry invalid credentials.
"""
ingest(db, "https://example.com/docs", "Acme Docs", sample)
for score, url, title, heading, body in search(db, "How should I handle rate limits?"):
print(f"{score:.3f}\t{heading}\t{url}\t{body}")