from db import get_db, return_db, get_setting, get_site_name, clean_url from templates import esc from ._helpers import _sanitize_fts_query, _paginate, _get_page_tags, _respond, _page_nav, PER_PAGE def handle_search(query): q = query.get("q", [""])[0].strip() page = _paginate(query) offset = (page - 1) * PER_PAGE db = get_db() try: count = db.execute("SELECT count(*) FROM pages").fetchone()[0] name = get_site_name() result_html = "" trusted_html = "" if q: try: fts_q = _sanitize_fts_query(q) bm25_rows = db.execute( "SELECT p.id, p.url, p.title, p.body, p.note " "FROM pages_fts f JOIN pages p ON f.rowid = p.id " "WHERE pages_fts MATCH ? " "ORDER BY bm25(pages_fts, 10.0, 1.0, 5.0, 3.0) LIMIT 100", (fts_q,), ).fetchall() except Exception: bm25_rows = [] bm25_ids = [r["id"] for r in bm25_rows] chunk_snippets = {} if get_setting("semantic_search", "0") == "1": try: from embeddings import hybrid_search use_reranker = get_setting("use_reranker", "1") == "1" fused = hybrid_search(q, bm25_ids, limit=100, db=db, use_reranker=use_reranker) fused_ids = [pid for pid, _ in fused] chunk_snippets = {pid: text for pid, text in fused if text} except Exception: fused_ids = bm25_ids else: fused_ids = bm25_ids # Also match by tag search_terms = [w.lower() for w in q.split() if w] if search_terms: placeholders = ",".join("?" * len(search_terms)) tag_rows = db.execute( f"SELECT DISTINCT pt.page_id FROM page_tags pt " f"JOIN tags t ON t.id = pt.tag_id " f"WHERE LOWER(t.name) IN ({placeholders})", search_terms, ).fetchall() tag_ids = {r["page_id"] for r in tag_rows} seen = set(fused_ids) for pid in tag_ids: if pid not in seen: fused_ids.append(pid) seen.add(pid) total_results = len(fused_ids) page_ids = fused_ids[offset:offset + PER_PAGE] if page_ids: placeholders = ",".join("?" * len(page_ids)) all_rows = db.execute( f"SELECT id, url, title, body, note, summary FROM pages WHERE id IN ({placeholders})", page_ids, ).fetchall() row_map = {r["id"]: r for r in all_rows} rows = [row_map[pid] for pid in page_ids if pid in row_map] else: rows = [] if rows: for r in rows: note_html = "" if r["note"]: note_html = f'
No results in your index.
" words = q.lower().split() all_links = db.execute( "SELECT l.url, l.label, p.title AS source_title " "FROM links l JOIN pages p ON l.page_id = p.id", ).fetchall() indexed_urls = set(r["url"] for r in rows) if rows else set() seen = set() trusted = [] for l in all_links: if l["url"] in indexed_urls or l["url"] in seen: continue if any(w in l["label"].lower() for w in words): seen.add(l["url"]) trusted.append(l) if len(trusted) >= 20: break if trusted: items = "" for l in trusted: items += ( f'Your index is empty.
' 'tinyweb is a personal search engine for pages you save. ' 'The index stays on your machine; so does every search.
' 'From here: add a page, ' 'get the bookmarklet, or ' 'subscribe to another instance.
' '