feat: RSS embeddings, semantic news in chat, article-to-chat, richer briefings
- Embed RSS items at fetch time (nomic-embed-text); backfill at startup
- Semantic news search injected into chat system prompt ("Recent News You've Seen")
when items match query above 0.55 cosine threshold (independent of note RAG)
- "Discuss in chat" button on news cards — creates a seeded conversation with
the article title + full content, navigates directly to the new chat
- Briefing compilation now passes 500-char article excerpts (not just headlines)
to the LLM and uses 8192 num_ctx to accommodate the larger prompt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -112,14 +112,18 @@ async def fetch_and_cache_feed(feed_id: int, url: str) -> int:
|
||||
# only writes to items it successfully classifies, so already-classified items
|
||||
# are not re-processed (they have classified_at set).
|
||||
unclassified_ids: list[int] = []
|
||||
new_item_data: list[tuple[int, str, str]] = [] # (id, title, content) for embedding
|
||||
if new_count > 0:
|
||||
result = await session.execute(
|
||||
select(RssItem.id).where(
|
||||
select(RssItem.id, RssItem.title, RssItem.content, RssItem.classified_at).where(
|
||||
RssItem.feed_id == feed_id,
|
||||
RssItem.classified_at.is_(None),
|
||||
)
|
||||
)
|
||||
unclassified_ids = list(result.scalars().all())
|
||||
for row in result.fetchall():
|
||||
item_id, title, content, classified_at = row
|
||||
if classified_at is None:
|
||||
unclassified_ids.append(item_id)
|
||||
new_item_data.append((item_id, title or "", content or ""))
|
||||
|
||||
# Prune old items to keep DB tidy
|
||||
await _prune_old_items(feed_id)
|
||||
@@ -129,6 +133,17 @@ async def fetch_and_cache_feed(feed_id: int, url: str) -> int:
|
||||
from fabledassistant.services.rss_classifier import classify_and_store
|
||||
asyncio.create_task(classify_and_store(unclassified_ids, feed_user_id))
|
||||
|
||||
# Fire-and-forget embedding for new items
|
||||
if new_item_data and feed_user_id is not None:
|
||||
from fabledassistant.services.embeddings import upsert_rss_item_embedding
|
||||
|
||||
async def _embed_new_items() -> None:
|
||||
for item_id, title, content in new_item_data:
|
||||
await upsert_rss_item_embedding(item_id, feed_user_id, title, content)
|
||||
await asyncio.sleep(0.05)
|
||||
|
||||
asyncio.create_task(_embed_new_items())
|
||||
|
||||
return new_count
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user