Initial commit: LinkVault – KI-gestützte Link-Sammlung
FastAPI + HTMX Web-App zum Speichern von Links mit automatischer KI-Kategorisierung, Zusammenfassung und semantischer Suche (OpenAI). Mehrbenutzer mit Login, SQLite-Persistenz, Docker/Docker-Compose-Setup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
36
app/search.py
Normal file
36
app/search.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import json
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def cosine_rank(query_vec: list[float], links: list) -> list[tuple]:
|
||||
"""Sortiere Links nach Kosinus-Ähnlichkeit zum Query-Vektor.
|
||||
|
||||
Liefert eine Liste aus (Link, Score), absteigend sortiert.
|
||||
Links ohne Embedding werden ignoriert.
|
||||
"""
|
||||
if not query_vec:
|
||||
return []
|
||||
|
||||
q = np.asarray(query_vec, dtype=float)
|
||||
q_norm = np.linalg.norm(q)
|
||||
if q_norm == 0:
|
||||
return []
|
||||
|
||||
ranked: list[tuple] = []
|
||||
for link in links:
|
||||
if not link.embedding:
|
||||
continue
|
||||
try:
|
||||
v = np.asarray(json.loads(link.embedding), dtype=float)
|
||||
except (ValueError, TypeError):
|
||||
continue
|
||||
if v.shape != q.shape:
|
||||
continue
|
||||
denom = q_norm * np.linalg.norm(v)
|
||||
if denom == 0:
|
||||
continue
|
||||
ranked.append((link, float(np.dot(q, v) / denom)))
|
||||
|
||||
ranked.sort(key=lambda item: item[1], reverse=True)
|
||||
return ranked
|
||||
Reference in New Issue
Block a user