feat: desk ia

This commit is contained in:
OpenSquared
2026-06-29 15:45:21 +02:00
parent 9c30b58f22
commit 69418ab650
7 changed files with 1238 additions and 3 deletions

View File

@@ -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."""