52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
"""Note summarizer — generates a compact AI summary for a note.
|
|
|
|
Called fire-and-forget from create_note / update_note tools so the
|
|
``notes.ai_summary`` column stays current without blocking the agent loop.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from langchain_core.messages import HumanMessage, SystemMessage
|
|
|
|
from app.core.langfuse_client import get_prompt_or_fallback
|
|
from app.core.llm import get_agent_llm
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_FALLBACK_PROMPT = """\
|
|
Summarize this note in <=250 characters. Be terse and dense.
|
|
Keep proper nouns, dates, decisions, and action items.
|
|
Do not start with "This note".
|
|
Respond with the summary text only — no intro, no labels.
|
|
|
|
Title: {title}
|
|
Content: {content}"""
|
|
|
|
_MAX_CONTENT_CHARS = 4000
|
|
|
|
|
|
async def generate_note_summary(title: str, content: str) -> str:
|
|
"""Return a <=250-char summary of *title* + *content*.
|
|
|
|
Uses the Langfuse ``note_summary`` prompt (hot-swappable) with a local
|
|
fallback. Truncates *content* to 4000 chars before sending to avoid
|
|
token waste on large notes.
|
|
"""
|
|
template, _ = get_prompt_or_fallback("note_summary", _FALLBACK_PROMPT)
|
|
trimmed = content[:_MAX_CONTENT_CHARS]
|
|
system_prompt = template.format(title=title, content=trimmed)
|
|
|
|
try:
|
|
llm = get_agent_llm("note-summarizer")
|
|
response = await llm.ainvoke([
|
|
SystemMessage(content=system_prompt),
|
|
HumanMessage(content="Generate the summary."),
|
|
])
|
|
text = response.content if isinstance(response.content, str) else ""
|
|
return text.strip()[:250]
|
|
except Exception as exc:
|
|
logger.warning("note_summarizer: failed to generate summary: %s", exc)
|
|
return ""
|