You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
"""Prompt registry for LLM parsing."""
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
PROMPT_VERSION = "v1"
|
|
|
|
_SYSTEM_EVENT_CLASSIFIER = """\
|
|
You are a financial document analyst specializing in SEC filings (8-K, 6-K).
|
|
Your task is to classify events and extract structured information from earnings press releases
|
|
and other material corporate disclosures.
|
|
|
|
Output ONLY valid JSON matching the specified schema. Do not add commentary outside the JSON.
|
|
""".strip()
|
|
|
|
_USER_EVENT_CLASSIFIER = """\
|
|
Analyze the following corporate filing excerpt and return a JSON object with these fields:
|
|
|
|
- event_type: one of ["earnings_release", "guidance_update", "material_contract",
|
|
"regulatory_or_approval", "capital_markets_or_financing", "management_change",
|
|
"litigation_or_investigation", "other_material_event", "unknown"]
|
|
- event_direction: one of ["bullish", "bearish", "mixed", "neutral", "unknown"]
|
|
- headline: short 1-sentence headline (max 120 chars)
|
|
- summary: 2-3 sentence summary of the key facts
|
|
- guidance_status: one of ["raised", "inline_or_maintained", "lowered", "withdrawn",
|
|
"not_provided", "unclear"]
|
|
- guidance_scope: one of ["quarterly", "annual", "both", "unknown"]
|
|
- demand_strength: one of ["strong", "stable", "weakening", "unknown"]
|
|
- pricing_power: one of ["present", "mixed", "absent", "unknown"]
|
|
- backlog_or_bookings: one of ["present", "mixed", "absent", "unknown"]
|
|
- customer_expansion: one of ["present", "mixed", "absent", "unknown"]
|
|
- margin_quality: one of ["improving", "stable", "deteriorating", "unknown"]
|
|
- oneoff_item: true/false — unusual one-time item inflating results
|
|
- tax_benefit: true/false
|
|
- valuation_gain: true/false
|
|
- non_gaap_heavy: true/false — results rely heavily on non-GAAP metrics
|
|
- financing_related: true/false
|
|
- legal_or_regulatory_overhang: true/false
|
|
- confidence_overall: float 0.0-1.0
|
|
- confidence_event_type: float 0.0-1.0
|
|
- confidence_event_direction: float 0.0-1.0
|
|
|
|
Document metadata:
|
|
Form type: {form_type}
|
|
Filing date: {filing_date}
|
|
Time bucket: {filing_time_bucket}
|
|
Rule hints: {rule_hints}
|
|
|
|
Filing text (truncated to {max_chars} chars):
|
|
---
|
|
{text}
|
|
---
|
|
|
|
Return ONLY the JSON object.
|
|
""".strip()
|
|
|
|
PROMPT_REGISTRY: dict[str, dict[str, Any]] = {
|
|
"event_classifier_v1": {
|
|
"version": PROMPT_VERSION,
|
|
"system": _SYSTEM_EVENT_CLASSIFIER,
|
|
"user_template": _USER_EVENT_CLASSIFIER,
|
|
}
|
|
}
|
|
|
|
|
|
def render_prompt(
|
|
prompt_name: str,
|
|
doc_meta: dict[str, Any],
|
|
text: str,
|
|
rule_hints: dict[str, Any],
|
|
max_chars: int = 8000,
|
|
) -> list[dict[str, str]]:
|
|
"""Render a named prompt into an Ollama messages list.
|
|
|
|
Args:
|
|
prompt_name: Key in PROMPT_REGISTRY.
|
|
doc_meta: Document metadata dict (form_type, filing_date, filing_time_bucket).
|
|
text: Exhibit text (will be truncated to max_chars).
|
|
rule_hints: Summary of rule parser output for context.
|
|
max_chars: Max characters of text to include.
|
|
|
|
Returns:
|
|
List of {role, content} dicts for Ollama chat API.
|
|
"""
|
|
entry = PROMPT_REGISTRY[prompt_name]
|
|
user_content = entry["user_template"].format(
|
|
form_type=doc_meta.get("form_type", "unknown"),
|
|
filing_date=doc_meta.get("filing_date", "unknown"),
|
|
filing_time_bucket=doc_meta.get("filing_time_bucket", "unknown"),
|
|
rule_hints=rule_hints,
|
|
text=text[:max_chars],
|
|
max_chars=max_chars,
|
|
)
|
|
return [
|
|
{"role": "system", "content": entry["system"]},
|
|
{"role": "user", "content": user_content},
|
|
]
|