Spaces:
Running
Running
| from __future__ import annotations | |
| from app.db.postgres import get_readonly_connection | |
| async def get_article_detail(article_id: int) -> dict: | |
| """ | |
| Resolves a single article's full title/snippet/metadata for citation | |
| display. Used by the agent post-processing step to enrich raw | |
| article_id references into full source objects. | |
| Returns: {"rows": [...], "source_refs": [{"type": "article", "id": ...}]} | |
| (kept in the same shape as sql_tool/graph_tool for consistency, even | |
| though this always returns 0 or 1 row.) | |
| """ | |
| query = """ | |
| SELECT id, title, url, published_at, content | |
| FROM news_articles | |
| WHERE id = %s | |
| """ | |
| async with get_readonly_connection() as conn: | |
| cur = await conn.execute(query, (article_id,)) | |
| row = await cur.fetchone() | |
| if row is None: | |
| return {"rows": [], "source_refs": []} | |
| columns = [desc[0] for desc in cur.description] | |
| article = dict(zip(columns, row)) | |
| # Truncate content into a short snippet — don't return full article text | |
| # for a citation lookup, keep responses lean | |
| snippet = (article.get("content") or "")[:280] | |
| if len(article.get("content") or "") > 280: | |
| snippet += "..." | |
| return { | |
| "rows": [{ | |
| "id": article["id"], | |
| "title": article["title"], | |
| "url": article["url"], | |
| "published_at": ( | |
| article["published_at"].isoformat() | |
| if article.get("published_at") else None | |
| ), | |
| "snippet": snippet, | |
| }], | |
| "source_refs": [{"type": "article", "id": article["id"]}], | |
| } | |