"""cf-harvest knowledge ingest + query endpoints.""" from __future__ import annotations import json from typing import Optional from fastapi import APIRouter, Depends, HTTPException, Query from app.core.config import settings from app.db.store import Store from app.models.schemas.knowledge import ( IngestResponse, KnowledgeFactOut, KnowledgeIngestRequest, ) from app.services.knowledge.ingest import ingest router = APIRouter() def _get_store() -> Store: s = Store(settings.DB_PATH) try: yield s finally: s.close() @router.post("/glean", response_model=IngestResponse) async def ingest_knowledge( body: KnowledgeIngestRequest, store: Store = Depends(_get_store) ): return ingest(store.conn, body) @router.get("", response_model=list[KnowledgeFactOut]) async def query_knowledge( fact_type: Optional[str] = Query(None), subject: Optional[str] = Query(None), presenter: Optional[str] = Query(None), min_confidence: Optional[float] = Query(None, ge=0.0, le=1.0), limit: int = Query(50, ge=1, le=500), offset: int = Query(0, ge=0), store: Store = Depends(_get_store), ): conditions = [] params: list = [] if fact_type: conditions.append("kf.fact_type = ?") params.append(fact_type) if subject: conditions.append("kf.subject LIKE ?") params.append(f"%{subject}%") if presenter: conditions.append("kf.presenter LIKE ?") params.append(f"%{presenter}%") if min_confidence is not None: conditions.append("kf.confidence >= ?") params.append(min_confidence) where = ("WHERE " + " AND ".join(conditions)) if conditions else "" params += [limit, offset] rows = store.conn.execute( f""" SELECT kf.*, ks.video_path, ks.location FROM knowledge_facts kf LEFT JOIN knowledge_sources ks ON ks.id = kf.source_id {where} ORDER BY kf.created_at DESC LIMIT ? OFFSET ? """, params, ).fetchall() result = [] for row in rows: d = store._row_to_dict(row) d["payload"] = json.loads(d["payload"]) result.append(d) return result @router.get("/{fact_id}", response_model=KnowledgeFactOut) async def get_knowledge_fact(fact_id: int, store: Store = Depends(_get_store)): row = store.conn.execute( """ SELECT kf.*, ks.video_path, ks.location FROM knowledge_facts kf LEFT JOIN knowledge_sources ks ON ks.id = kf.source_id WHERE kf.id = ? """, (fact_id,), ).fetchone() if not row: raise HTTPException(status_code=404, detail="Knowledge fact not found") d = store._row_to_dict(row) d["payload"] = json.loads(d["payload"]) return d