agentic-os/newspaper-extractor/backend/app/api/routes_search.py

49 lines
2.0 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, Body
from sqlalchemy import or_, text
from app.db.session import get_db
from app.pipeline.enricher import Enricher
router = APIRouter(prefix="/api")
enricher = Enricher()
@router.get("/search")
def search(q: str = "", category: str = None, person: str = None,
date: str = None, page: int = None, job_id: int = None, semantic: bool = False, db=Depends(get_db)):
from app.db.models import Article
query = db.query(Article)
if category: query = query.filter(Article.category == category)
if date: query = query.filter(Article.date == date)
if page: query = query.filter(Article.page == page)
if job_id: query = query.filter(Article.upload_job_id == job_id)
if person: query = query.filter(Article.persons.any(person))
if q and not semantic:
query = query.filter(or_(Article.headline.ilike(f"%{q}%"),
Article.text.ilike(f"%{q}%")))
return query.limit(50).all()
if semantic and q:
vec = enricher.embed(q)
# pgvector cosine distance
return db.execute(text("""
SELECT * FROM articles ORDER BY embedding <=> :v LIMIT 30
"""), {"v": str(vec)}).fetchall()
return query.limit(50).all()
@router.put("/articles/{article_id}")
def update_article(article_id: int, updates: dict = Body(...), db=Depends(get_db)):
from app.db.models import Article
article = db.query(Article).filter(Article.id == article_id).first()
if not article:
raise HTTPException(status_code=404, detail="Article not found")
# Update allowed fields
allowed = ["headline", "category", "subcategory", "summary", "sentiment", "keywords", "persons", "locations", "organizations"]
for k, v in updates.items():
if k in allowed:
setattr(article, k, v)
# Mark as verified for RAG training
article.human_verified = True
db.commit()
db.refresh(article)
return article