feat: market event
This commit is contained in:
@@ -257,7 +257,11 @@ def _gpt4o_recommend(event: dict, templates: list) -> dict:
|
|||||||
system_prompt = (
|
system_prompt = (
|
||||||
"You are a macro market analyst and causal graph specialist for the GeoOptions platform. "
|
"You are a macro market analyst and causal graph specialist for the GeoOptions platform. "
|
||||||
"Given a market event and a library of causal graph templates, recommend the most appropriate template "
|
"Given a market event and a library of causal graph templates, recommend the most appropriate template "
|
||||||
"and suggest any coefficient adjustments. Respond with a JSON object only."
|
"and suggest any coefficient adjustments. Respond with a JSON object only.\n"
|
||||||
|
"IMPORTANT: Only recommend a template if it is structurally compatible with the event type "
|
||||||
|
"(same causal mechanism — e.g. do NOT recommend an ECB rate decision template for a sentiment survey). "
|
||||||
|
"If no template fits well (structural mismatch, confidence < 0.6), set template_id to null "
|
||||||
|
"and explain in 'notes' what kind of template would be needed."
|
||||||
)
|
)
|
||||||
|
|
||||||
user_prompt = f"""Market event to analyze:
|
user_prompt = f"""Market event to analyze:
|
||||||
@@ -875,6 +879,15 @@ def analyze_event(body: AnalyzeRequest):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# Sources legacy
|
# Sources legacy
|
||||||
|
elif src == "surprise_bps" and event.get("surprise_pct") is not None:
|
||||||
|
# Valeur brute en bps (ex: écart taux BCE en points de base)
|
||||||
|
raw = float(event["surprise_pct"])
|
||||||
|
node_range = cfg.get("range")
|
||||||
|
if node_range and len(node_range) == 2:
|
||||||
|
lo, hi = float(node_range[0]), float(node_range[1])
|
||||||
|
inputs[input_id] = round(max(lo, min(hi, raw)), 4)
|
||||||
|
else:
|
||||||
|
inputs[input_id] = round(raw, 4)
|
||||||
elif src == "surprise" and event.get("surprise_pct") is not None:
|
elif src == "surprise" and event.get("surprise_pct") is not None:
|
||||||
raw = float(event["surprise_pct"])
|
raw = float(event["surprise_pct"])
|
||||||
node_range = cfg.get("range")
|
node_range = cfg.get("range")
|
||||||
|
|||||||
@@ -509,8 +509,32 @@ function EventDetail({
|
|||||||
setRecMsg(`✓ ${rec.template_name}${rec.confidence ? ` (${Math.round(rec.confidence * 100)}%)` : ''}`)
|
setRecMsg(`✓ ${rec.template_name}${rec.confidence ? ` (${Math.round(rec.confidence * 100)}%)` : ''}`)
|
||||||
await instantiate(rec.template_id)
|
await instantiate(rec.template_id)
|
||||||
} else {
|
} else {
|
||||||
setRecMsg('Aucun template adapté trouvé')
|
// Aucun template adapté — création automatique d'un nouveau
|
||||||
setNoTemplateFound(true)
|
setRecMsg('Aucun template adapté — création en cours…')
|
||||||
|
setNoTemplateFound(false)
|
||||||
|
setLoadingCreate(true)
|
||||||
|
try {
|
||||||
|
const cr = await fetch('/api/causal-lab/create-from-event', {
|
||||||
|
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ market_event_id: detail.id }),
|
||||||
|
})
|
||||||
|
const cd = await cr.json()
|
||||||
|
if (!cr.ok) throw new Error(cd.detail || cr.statusText)
|
||||||
|
const newTmplId = cd.template?.id ?? cd.template_id
|
||||||
|
if (newTmplId) {
|
||||||
|
setTemplates(prev => [...prev, cd.template].filter(Boolean))
|
||||||
|
setSelTmpl(newTmplId)
|
||||||
|
setRecMsg(`✦ Nouveau template créé : ${cd.template?.name ?? 'template'}`)
|
||||||
|
await instantiate(newTmplId)
|
||||||
|
} else {
|
||||||
|
setRecMsg('Template créé mais ID manquant')
|
||||||
|
}
|
||||||
|
} catch (ce: any) {
|
||||||
|
setRecMsg(`✗ Création échouée : ${ce.message}`)
|
||||||
|
setNoTemplateFound(true)
|
||||||
|
} finally {
|
||||||
|
setLoadingCreate(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: any) { setRecMsg(`✗ ${(e as any).message}`) }
|
} catch (e: any) { setRecMsg(`✗ ${(e as any).message}`) }
|
||||||
finally { setLoadingRec(false) }
|
finally { setLoadingRec(false) }
|
||||||
|
|||||||
Reference in New Issue
Block a user