68 lines
2.6 KiB
Python
68 lines
2.6 KiB
Python
"""LLM prompt for AI report commentary.
|
|
|
|
Provider-agnostic system + user prompt builder. Output contract:
|
|
JSON with keys summary, highlights, concerns, next_actions."""
|
|
|
|
|
|
SYSTEM_PROMPT = """You are an experienced CFO providing executive-level commentary
|
|
on a financial report. Your output MUST be valid JSON of this exact shape:
|
|
|
|
{
|
|
"summary": "<2-3 sentence executive summary of the report period>",
|
|
"highlights": ["<observation 1>", "<observation 2>", ...],
|
|
"concerns": ["<thing to investigate 1>", ...],
|
|
"next_actions": ["<suggested action 1>", ...]
|
|
}
|
|
|
|
Rules:
|
|
- Use the data provided. Do not invent numbers.
|
|
- Tone: professional, concise, factual.
|
|
- Currency formatting: always include the $ symbol and 2 decimal places.
|
|
- For anomalies: explicitly mention the variance percentage AND the dollar amount.
|
|
- Do NOT include markdown code fences. Do NOT include any prose outside the JSON.
|
|
"""
|
|
|
|
|
|
def build_prompt(report_result: dict, anomalies: list) -> tuple[str, str]:
|
|
"""Build (system_prompt, user_prompt) tuple."""
|
|
parts = []
|
|
|
|
# Report context
|
|
parts.append(f"REPORT: {report_result.get('report_name', 'Untitled')}")
|
|
period = report_result.get('period', {})
|
|
parts.append(f"PERIOD: {period.get('label', '')} "
|
|
f"({period.get('date_from', '')} to {period.get('date_to', '')})")
|
|
comp_period = report_result.get('comparison_period')
|
|
if comp_period:
|
|
parts.append(f"COMPARED TO: {comp_period.get('label', '')} "
|
|
f"({comp_period.get('date_from', '')} to {comp_period.get('date_to', '')})")
|
|
parts.append("")
|
|
|
|
# Rows (the actual numbers)
|
|
parts.append("REPORT LINES:")
|
|
for row in report_result.get('rows', []):
|
|
line = f" - {row.get('label', '?')}: ${row.get('amount', 0):,.2f}"
|
|
if row.get('amount_comparison') is not None:
|
|
line += f" (comparison: ${row['amount_comparison']:,.2f}"
|
|
if row.get('variance_pct') is not None:
|
|
line += f", {row['variance_pct']:+.1f}%"
|
|
line += ")"
|
|
if row.get('is_subtotal'):
|
|
line += " [SUBTOTAL]"
|
|
parts.append(line)
|
|
parts.append("")
|
|
|
|
# Anomalies
|
|
if anomalies:
|
|
parts.append("ANOMALIES (variances exceeding threshold):")
|
|
for a in anomalies[:10]:
|
|
parts.append(
|
|
f" - {a['label']}: {a['direction']}d {a['variance_pct']:.1f}% "
|
|
f"(${a['variance_amount']:+,.2f}, severity: {a['severity']})"
|
|
)
|
|
parts.append("")
|
|
|
|
parts.append("Generate the JSON commentary per the system prompt.")
|
|
|
|
return (SYSTEM_PROMPT, "\n".join(parts))
|