PHP Classes

File: tools/support-bot/query_retrieve.py

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   tools/support-bot/query_retrieve.py   Download  
File: tools/support-bot/query_retrieve.py
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 6,185 bytes
 

Contents

Class file image Download
#!/usr/bin/env python3 """ query_retrieve.py - Embeds a question and retrieves the top-K most relevant chunks from binkterm_knowledge.db using sqlite-vec cosine similarity. Returns a JSON array of chunk objects to stdout. Usage: python3 query_retrieve.py <question> [top_k] [db_path] """ import json import os import re import sqlite3 import struct import sys import urllib.request import urllib.error try: import sqlite_vec except ImportError: print("Error: sqlite_vec not installed. Run: pip install sqlite-vec", file=sys.stderr) sys.exit(1) DEFAULT_DB = os.path.join(os.path.dirname(__file__), "binkterm_knowledge.db") MODEL_NAME = "sentence-transformers/all-MiniLM-L6-v2" EMBED_SERVER = "http://127.0.0.1:5001" MIN_CONTENT_CHARS = 80 MIN_CANDIDATES = 100 VERSION_RE = re.compile(r"\b\d+\.\d+\.\d+\b") def pack_vector(vec: list[float]) -> bytes: return struct.pack(f"{len(vec)}f", *vec) def embed_via_server(text: str) -> list | None: """Return embedding from the daemon, or None if unreachable.""" try: urllib.request.urlopen(f"{EMBED_SERVER}/health", timeout=1).close() except (urllib.error.URLError, OSError): return None payload = json.dumps({"text": text}).encode("utf-8") req = urllib.request.Request( f"{EMBED_SERVER}/embed", data=payload, headers={"Content-Type": "application/json"}, method="POST", ) try: with urllib.request.urlopen(req, timeout=10) as resp: return json.loads(resp.read()) except (urllib.error.URLError, OSError, json.JSONDecodeError): return None def embed_local(text: str) -> list: """Load the same local model used at index-build time and return the embedding.""" try: from fastembed import TextEmbedding except ImportError: print("Error: fastembed not installed. Run: pip install -r requirements.txt", file=sys.stderr) sys.exit(1) model = TextEmbedding(MODEL_NAME) return next(iter(model.embed([text]))).tolist() def rerank_chunks(question: str, rows: list[tuple]) -> list[dict]: """ Rerank vector-search candidates so contentful chunks from an exact version-matched upgrade document outrank empty section-heading chunks. """ versions = VERSION_RE.findall(question) scored_rows: list[tuple[float, tuple]] = [] for row in rows: source, heading_context, content, distance = row heading = heading_context or "" stripped_content = content.strip() score = float(distance) if len(stripped_content) < MIN_CONTENT_CHARS: score += 0.35 if "table of contents" in heading.lower(): score += 0.35 if "upgrade instructions" in heading.lower(): score += 0.25 if "summary of changes >" in heading.lower() and len(stripped_content) >= MIN_CONTENT_CHARS: score -= 0.15 for version in versions: if version in source: score -= 0.60 if version in heading: score -= 0.20 scored_rows.append((score, row)) scored_rows.sort(key=lambda item: (item[0], item[1][3])) ranked_chunks = [ { "source": row[0], "heading_context": row[1] or "", "content": row[2], "distance": row[3], } for _, row in scored_rows ] def is_exact_version_match(chunk: dict) -> bool: return any( version in chunk["source"] or version in chunk["heading_context"] for version in versions ) def is_substantive(chunk: dict) -> bool: heading = chunk["heading_context"].lower() return ( len(chunk["content"].strip()) >= MIN_CONTENT_CHARS and "table of contents" not in heading ) def is_summary_detail(chunk: dict) -> bool: return "summary of changes >" in chunk["heading_context"].lower() exact_version_chunks = [chunk for chunk in ranked_chunks if is_exact_version_match(chunk)] other_chunks = [chunk for chunk in ranked_chunks if chunk not in exact_version_chunks] ordered_chunks = ( [chunk for chunk in exact_version_chunks if is_substantive(chunk) and is_summary_detail(chunk)] + [chunk for chunk in exact_version_chunks if is_substantive(chunk) and not is_summary_detail(chunk)] + [chunk for chunk in exact_version_chunks if not is_substantive(chunk)] + [chunk for chunk in other_chunks if is_substantive(chunk) and is_summary_detail(chunk)] + [chunk for chunk in other_chunks if is_substantive(chunk) and not is_summary_detail(chunk)] + [chunk for chunk in other_chunks if not is_substantive(chunk)] ) return ordered_chunks if __name__ == "__main__": if len(sys.argv) < 2 or not sys.argv[1].strip(): print("Usage: query_retrieve.py <question> [top_k] [db_path]", file=sys.stderr) sys.exit(1) question = sys.argv[1] top_k = int(sys.argv[2]) if len(sys.argv) > 2 else 4 db_path = sys.argv[3] if len(sys.argv) > 3 else DEFAULT_DB if not os.path.exists(db_path): print(f"Error: database not found: {db_path}", file=sys.stderr) sys.exit(1) vec = embed_via_server(question) if vec is None: print("embed_server not reachable, loading model locally (this takes ~15s)", file=sys.stderr) vec = embed_local(question) else: print("embed_server hit OK", file=sys.stderr) blob = pack_vector(vec) con = sqlite3.connect(db_path) con.enable_load_extension(True) sqlite_vec.load(con) con.enable_load_extension(False) candidate_k = max(top_k * 25, MIN_CANDIDATES) rows = con.execute(""" SELECT c.source, c.heading_context, c.content, v.distance FROM chunks_vec v JOIN chunks c ON c.id = v.rowid WHERE v.embedding MATCH ? AND k = ? ORDER BY v.distance """, [blob, candidate_k]).fetchall() con.close() chunks = rerank_chunks(question, rows)[:top_k] print(json.dumps(chunks))