FastAPI + Celery + Next.js + Postgres/Redis app with company monitoring, source collection, LLM-based change analysis, enrichment, and account security (Turnstile, escalating lockout, email verification).
61 lines
2.3 KiB
Python
61 lines
2.3 KiB
Python
"""Task E: change significance narrative.
|
|
|
|
Severity itself stays deterministic (app/change_detection/scoring.py) - see
|
|
ARCHITECTURE.md: "the LLM narrates why a change matters; it does not decide
|
|
how much it matters." This task supplies the narrative explanation and a
|
|
second, independent opinion on whether the change looks real/meaningful and
|
|
notification-worthy, which the notification layer (Phase 8) can use as an
|
|
extra signal alongside the deterministic severity - it never overrides it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from app.analysis.llm.base import LLMProvider
|
|
from app.prompts.base import build_user_prompt
|
|
|
|
SYSTEM_PROMPT = (
|
|
"You are a competitive intelligence analyst reviewing one detected change between two "
|
|
"snapshots of a company's public information. Explain in plain language why this change "
|
|
"would or wouldn't matter to someone monitoring this company, given their stated focus. "
|
|
"Be honest about uncertainty - do not overstate a routine wording tweak as significant, "
|
|
"and do not undersell a genuine signal."
|
|
)
|
|
|
|
|
|
class ChangeSignificanceAssessment(BaseModel):
|
|
is_real_change: bool = Field(description="Does this look like a genuine change, not noise?")
|
|
is_meaningful: bool
|
|
why_it_matters: str
|
|
confidence: float = Field(ge=0.0, le=1.0)
|
|
should_notify: bool
|
|
|
|
|
|
async def assess_change_significance(
|
|
llm: LLMProvider,
|
|
*,
|
|
company_name: str,
|
|
monitoring_focus: str | None,
|
|
change_type: str,
|
|
change_summary: str,
|
|
added_text: list[str],
|
|
removed_text: list[str],
|
|
deterministic_severity: str,
|
|
deterministic_confidence: float,
|
|
) -> ChangeSignificanceAssessment:
|
|
evidence = {
|
|
"company_name": company_name,
|
|
"monitoring_focus": monitoring_focus,
|
|
"change_type": change_type,
|
|
"change_summary": change_summary,
|
|
"text_added": added_text[:20],
|
|
"text_removed": removed_text[:20],
|
|
"deterministic_severity": deterministic_severity,
|
|
"deterministic_confidence": deterministic_confidence,
|
|
}
|
|
user_prompt = build_user_prompt(
|
|
"Assess this detected change and explain why it does or doesn't matter.", evidence
|
|
)
|
|
return await llm.generate_structured(SYSTEM_PROMPT, user_prompt, ChangeSignificanceAssessment)
|