mirror of
https://github.com/caty21/forex-dashboard.git
synced 2026-08-04 16:27:43 +00:00
3a39904ce5
Indicateurs : - JPY CPI : null → IMF/IFS DBnomics MoM% (override 0.1% mai 2026) - AUD CPI : mauvais ID FRED (AUSCPIALLMINMEI→AUSCPIALLQINMEI) + override 1.4% T1 2026 - NZD CPI : mauvais ID FRED (NZLCPIALLMINMEI→NZLCPIALLQINMEI) + override 0.9% T1 2026 - Nouveau data/cpi_overrides.json — surcharge manuelle quand FRED/DBnomics en retard - Override date-comparé : source auto reprend quand elle dépasse l'override Taux directeurs : - GBP : BoE API IUDBEDR primary + IR3TIB01GBM156N fallback FRED (IRSTCB01 inexistant) - USD/EUR/CAD/NZD : sources déduplicées (DFEDTARU, ECBDFR, BoC Valet, IRSTCB01) Zone Euro : - EUR CPI fallback : prc_hicp_mmr (404) → prc_hicp_midx + toIndicatorPct - EUR chômage : geo=EA21 (2026) + fallback EA20 Expectations : - data/rate_expectations.json : données correctes 29/05/2026 (Fed 68bps, ECB 49bps, BoE 53bps, BoJ +32bps, etc.) UI : - Tooltip bps : explication "1 bp = 0,01% de taux" - NarrativeButton : affiche le vrai message d'erreur (était "Erreur Bytez") - Groq API key manquante : message descriptif avec chemin Vercel Types : - IndicatorResult type explicite → corrige erreurs tsc pre-existantes (prev/lastUpdated) - toPmiIndicator retourne IndicatorResult Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
101 lines
3.4 KiB
TypeScript
101 lines
3.4 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import OpenAI from "openai";
|
|
|
|
// Groq — API OpenAI-compatible, niveau gratuit, modèles Llama
|
|
const groq = new OpenAI({
|
|
apiKey: process.env.GROQ_API_KEY ?? "",
|
|
baseURL: "https://api.groq.com/openai/v1",
|
|
});
|
|
|
|
const SYSTEM_PROMPT = `Tu es un analyste macro Forex senior. Tu analyses les données macroéconomiques de 8 devises majeures (USD, EUR, GBP, JPY, CHF, CAD, AUD, NZD) et tu fournis des synthèses concises et actionnables pour un trader particulier.
|
|
|
|
Tes analyses sont :
|
|
- Directes et factuelles — pas de conditionnel excessif
|
|
- Structurées en 3-4 points maximum
|
|
- Focalisées sur les divergences et signaux de trading
|
|
- En français
|
|
- Sans disclaimers légaux
|
|
|
|
Format de réponse : texte court, 80-120 mots maximum par devise.`;
|
|
|
|
export async function POST(req: NextRequest) {
|
|
const apiKey = process.env.GROQ_API_KEY;
|
|
if (!apiKey) {
|
|
return NextResponse.json({ error: "GROQ_API_KEY manquant — ajouter dans Vercel → Settings → Environment Variables" }, { status: 503 });
|
|
}
|
|
|
|
let body: {
|
|
mode: "cb_analysis" | "expert_opinion" | "summary" | "divergence";
|
|
currency?: string;
|
|
data?: unknown;
|
|
userInput?: string;
|
|
};
|
|
|
|
try {
|
|
body = await req.json();
|
|
} catch {
|
|
return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
}
|
|
|
|
const { mode, currency, data, userInput } = body;
|
|
|
|
let userMessage = "";
|
|
|
|
switch (mode) {
|
|
case "cb_analysis":
|
|
userMessage = `Analyse le communiqué de la banque centrale pour ${currency}.
|
|
Données contextuelles : ${JSON.stringify(data, null, 2)}
|
|
|
|
Fournis une analyse en 4 points :
|
|
1. Changement de ton (hawkish/dovish/neutre)
|
|
2. Évolution des projections de taux
|
|
3. Phrases clés ajoutées ou supprimées vs précédent
|
|
4. Impact suggéré sur ${currency} (+1 haussier / 0 neutre / -1 baissier)`;
|
|
break;
|
|
|
|
case "expert_opinion":
|
|
userMessage = `Point de Vérité — Confrontation IA :
|
|
Avis expert injecté : "${userInput}"
|
|
Données actuelles du dashboard pour ${currency} : ${JSON.stringify(data, null, 2)}
|
|
|
|
Analyse :
|
|
- Convergences entre l'avis expert et les données quantitatives
|
|
- Divergences et points de tension
|
|
- Score avant/après ajustement suggéré
|
|
- Validation ou rejet de l'avis par devise`;
|
|
break;
|
|
|
|
case "divergence":
|
|
userMessage = `Analyse les divergences de positionnement détectées pour ${currency} :
|
|
${JSON.stringify(data, null, 2)}
|
|
|
|
Explique en 3 phrases : pourquoi cette configuration est significative et quelle action de trading elle suggère.`;
|
|
break;
|
|
|
|
case "summary":
|
|
default:
|
|
userMessage = `Génère une synthèse macro hebdomadaire pour ${currency} basée sur ces données :
|
|
${JSON.stringify(data, null, 2)}
|
|
|
|
Résumé en 3 points : situation actuelle, signal directionnel, risque principal.`;
|
|
}
|
|
|
|
try {
|
|
const completion = await groq.chat.completions.create({
|
|
model: "llama-3.1-8b-instant",
|
|
messages: [
|
|
{ role: "system", content: SYSTEM_PROMPT },
|
|
{ role: "user", content: userMessage },
|
|
],
|
|
max_tokens: 300,
|
|
temperature: 0.3,
|
|
});
|
|
|
|
const text = completion.choices[0]?.message?.content ?? "";
|
|
return NextResponse.json({ analysis: text, model: completion.model, mode });
|
|
} catch (err: unknown) {
|
|
const message = err instanceof Error ? err.message : String(err);
|
|
return NextResponse.json({ error: `Groq error: ${message}` }, { status: 502 });
|
|
}
|
|
}
|