feat: desk ia
This commit is contained in:
@@ -1125,6 +1125,108 @@ def _build_graph_json_from_spec(spec: dict) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def auto_assign_template(event_id: int) -> dict:
|
||||
"""
|
||||
Auto-assign or auto-create a causal template for a market event.
|
||||
Called by the eco detector when auto_template=True in desk config.
|
||||
Returns {"template_id": int, "action": "assigned"|"created", "name": str} or {"error": ...}
|
||||
"""
|
||||
try:
|
||||
from services.database import get_conn, get_config
|
||||
from services.causal_graphs import get_templates, init_tables, seed_templates
|
||||
import openai
|
||||
|
||||
key = get_config("openai_api_key") or ""
|
||||
if not key:
|
||||
return {"error": "Clé OpenAI manquante"}
|
||||
|
||||
conn = get_conn()
|
||||
init_tables(conn)
|
||||
seed_templates(conn)
|
||||
|
||||
ev_row = conn.execute("SELECT * FROM market_events WHERE id = ?", (event_id,)).fetchone()
|
||||
if not ev_row:
|
||||
conn.close()
|
||||
return {"error": f"Event {event_id} introuvable"}
|
||||
|
||||
event = dict(ev_row)
|
||||
templates = get_templates(conn)
|
||||
|
||||
# Step 1 — recommend an existing template
|
||||
recommendation = _gpt4o_recommend(event, templates)
|
||||
tmpl_id = recommendation.get("template_id")
|
||||
confidence = float(recommendation.get("confidence") or 0.0)
|
||||
|
||||
if tmpl_id and confidence >= 0.6:
|
||||
conn.execute("UPDATE market_events SET template_id = ? WHERE id = ?", (tmpl_id, event_id))
|
||||
conn.commit()
|
||||
row = conn.execute("SELECT name FROM causal_graph_templates WHERE id = ?", (tmpl_id,)).fetchone()
|
||||
conn.close()
|
||||
return {"template_id": tmpl_id, "action": "assigned", "name": row["name"] if row else "", "confidence": confidence}
|
||||
|
||||
# Step 2 — no good match → generate a new template
|
||||
conn.close()
|
||||
|
||||
client = openai.OpenAI(api_key=key)
|
||||
prompt = f"""Tu es un analyste financier spécialisé en graphes causaux macro.
|
||||
Crée un graphe causal pour l'événement suivant.
|
||||
|
||||
Événement :
|
||||
- Nom : {event.get('name')}
|
||||
- Catégorie : {event.get('category')} / {event.get('sub_type', '')}
|
||||
- Description : {(event.get('description') or '')[:400]}
|
||||
- Réel : {event.get('actual_value')} | Attendu : {event.get('expected_value')} | Surprise % : {event.get('surprise_pct')}
|
||||
|
||||
Retourne UNIQUEMENT ce JSON (sans commentaire ni markdown) :
|
||||
{{
|
||||
"name": "<nom court, ex: 'CPI US — Taux/USD'>",
|
||||
"category": "macro_us",
|
||||
"description": "<1 phrase décrivant le mécanisme>",
|
||||
"input_node": {{"id": "<snake_case>", "label": "<label court>", "unit": "<unité>"}},
|
||||
"intermediate_nodes": [{{"id": "<snake_case>", "label": "<label>", "coef_name": "<coef_snake_case>", "coef_value": 0.5, "coef_desc": "<description>"}}],
|
||||
"output_nodes": [{{"id": "<instr_lower>_pip", "label": "<INSTRUMENT>", "instrument": "<EURUSD|XAUUSD|SP500|BRENT|US10Y>", "source_intermediate": "<id>", "coef_name": "<coef_snake_case>", "coef_value": 100, "coef_desc": "<description>"}}]
|
||||
}}
|
||||
Règles : coef intermédiaire ∈ [-5,5] ; coef output en pips, |val| ∈ [30,200]."""
|
||||
|
||||
resp = client.chat.completions.create(
|
||||
model="gpt-4o",
|
||||
messages=[{"role": "user", "content": prompt}],
|
||||
response_format={"type": "json_object"},
|
||||
temperature=0.3,
|
||||
max_tokens=900,
|
||||
)
|
||||
spec = json.loads(resp.choices[0].message.content or "{}")
|
||||
|
||||
graph_json = _build_graph_json_from_spec(spec)
|
||||
category = spec.get("category", "macro_us")
|
||||
instruments = graph_json.get("instruments", ["EURUSD"])
|
||||
|
||||
conn2 = get_conn()
|
||||
cur = conn2.execute("""
|
||||
INSERT INTO causal_graph_templates
|
||||
(name, category, sub_type, description, instruments, graph_json, heuristic_ver)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 1)
|
||||
""", (
|
||||
spec.get("name", event.get("name", "Template IA")),
|
||||
category,
|
||||
event.get("sub_type", ""),
|
||||
spec.get("description", ""),
|
||||
json.dumps(instruments),
|
||||
json.dumps(graph_json),
|
||||
))
|
||||
new_id = cur.lastrowid
|
||||
conn2.execute("UPDATE market_events SET template_id = ? WHERE id = ?", (new_id, event_id))
|
||||
conn2.commit()
|
||||
conn2.close()
|
||||
|
||||
logger.info(f"[auto_template] Created template #{new_id} '{spec.get('name')}' for event #{event_id}")
|
||||
return {"template_id": new_id, "action": "created", "name": spec.get("name", "Template IA"), "confidence": confidence}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[auto_template] event #{event_id}: {e}")
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
@router.post("/api/causal-lab/create-from-event")
|
||||
def create_template_from_event(body: CreateFromEventRequest):
|
||||
"""GPT-4o génère et enregistre un template causal adapté à l'événement."""
|
||||
|
||||
Reference in New Issue
Block a user