mirror of
https://github.com/caty21/forex-dashboard.git
synced 2026-08-13 04:28:04 +00:00
feat: calendar prev week, fullscreen mode, AI weekly highlights
Calendar — "Semaine dernière" tab: - API now fetches from last Monday (instead of today) and tags events as "prev" - New tab in CalendarTab with last week's published events (actual values visible) - fromDate filter bypassed for prev tab; week banner styled in slate Dashboard — fullscreen: - Maximize2/Minimize2 button in header using Fullscreen API - Listens to fullscreenchange to sync icon state Report — AI "Faits marquants": - New report_highlights mode in /api/narrative: reads published events from prev+current week + drivers, generates 3 structured highlights via Groq - AiHighlightsButton next to "Faits marquants de la semaine" label - Parses AI response (-- delimited) into title+body Theme objects Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
ce53f97b5b
commit
a3d847ce59
@@ -32,7 +32,7 @@ export interface CalendarEvent {
|
||||
forecast: string | null;
|
||||
previous: string | null;
|
||||
isPublished: boolean;
|
||||
week: "current" | "next" | "next2"; // semaine de l'événement
|
||||
week: "prev" | "current" | "next" | "next2"; // semaine de l'événement
|
||||
source: "ff" | "fred"; // source de la donnée
|
||||
groupKey: string | null;
|
||||
isGroupParent: boolean;
|
||||
@@ -322,7 +322,17 @@ export async function GET() {
|
||||
const fredKey = process.env.FRED_API_KEY;
|
||||
const { nextMonday, next2Monday } = getWeekBounds();
|
||||
|
||||
const fromDate = new Date().toISOString().slice(0, 10);
|
||||
// Fetch depuis le lundi de la semaine précédente pour inclure "Semaine dernière"
|
||||
const now = new Date();
|
||||
const dayOfWeek = now.getDay(); // 0=dim, 1=lun…6=sam
|
||||
const daysToThisMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
|
||||
const thisMonday = new Date(now);
|
||||
thisMonday.setDate(now.getDate() - daysToThisMonday);
|
||||
thisMonday.setHours(0, 0, 0, 0);
|
||||
const lastMonday = new Date(thisMonday);
|
||||
lastMonday.setDate(thisMonday.getDate() - 7);
|
||||
|
||||
const fromDate = lastMonday.toISOString().slice(0, 10);
|
||||
const toDateObj = new Date();
|
||||
toDateObj.setDate(toDateObj.getDate() + 14);
|
||||
const toDate = toDateObj.toISOString().slice(0, 10);
|
||||
@@ -347,9 +357,10 @@ export async function GET() {
|
||||
|
||||
const events: CalendarEvent[] = [];
|
||||
|
||||
const weekOf = (date: Date): "current" | "next" | "next2" =>
|
||||
const weekOf = (date: Date): "prev" | "current" | "next" | "next2" =>
|
||||
date >= next2Monday ? "next2" :
|
||||
date >= nextMonday ? "next" : "current";
|
||||
date >= nextMonday ? "next" :
|
||||
date >= thisMonday ? "current" : "prev";
|
||||
|
||||
if (useScraping) {
|
||||
// ── BASE : TE HTML ────────────────────────────────────────────────────────
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
let body: {
|
||||
mode: "cb_analysis" | "expert_opinion" | "summary" | "divergence" | "report_ccy";
|
||||
mode: "cb_analysis" | "expert_opinion" | "summary" | "divergence" | "report_ccy" | "report_highlights";
|
||||
currency?: string;
|
||||
data?: unknown;
|
||||
userInput?: string;
|
||||
@@ -94,6 +94,41 @@ Rédige un paragraphe fluide de 80 à 120 mots, style analyste macro professionn
|
||||
break;
|
||||
}
|
||||
|
||||
case "report_highlights": {
|
||||
const d = data as {
|
||||
events?: Array<{ title: string; currency: string; actual?: string | null; forecast?: string | null; previous?: string | null; impact: string }>;
|
||||
drivers?: { vix?: number | null; brent?: number | null; us10y?: number | null };
|
||||
weekFrom?: string; weekTo?: string;
|
||||
};
|
||||
const published = (d.events ?? [])
|
||||
.filter(e => e.actual && e.impact !== "low")
|
||||
.slice(0, 12)
|
||||
.map(e => `${e.currency} · ${e.title} : actuel=${e.actual ?? "—"} / prévu=${e.forecast ?? "—"} / précédent=${e.previous ?? "—"}`)
|
||||
.join("\n");
|
||||
const weekRange = d.weekFrom && d.weekTo ? `${d.weekFrom} au ${d.weekTo}` : "de la semaine";
|
||||
userMessage = `Génère 3 faits marquants de la semaine du ${weekRange} pour un trader Forex G10.
|
||||
|
||||
Données publiées cette semaine :
|
||||
${published || "Aucune publication disponible"}
|
||||
|
||||
Contexte marché : VIX=${d.drivers?.vix?.toFixed(1) ?? "N/D"}, Brent=$${d.drivers?.brent?.toFixed(1) ?? "N/D"}, US 10Y=${d.drivers?.us10y?.toFixed(2) ?? "N/D"}%
|
||||
|
||||
Pour chaque fait marquant, fournis :
|
||||
- TITRE (6 mots max, en majuscules)
|
||||
- DESCRIPTION (30-40 mots) : chiffre clé, surprise vs consensus, impact sur les devises concernées
|
||||
|
||||
Formate ta réponse EXACTEMENT ainsi (3 blocs, séparés par --) :
|
||||
TITRE1
|
||||
Description1
|
||||
--
|
||||
TITRE2
|
||||
Description2
|
||||
--
|
||||
TITRE3
|
||||
Description3`;
|
||||
break;
|
||||
}
|
||||
|
||||
case "summary":
|
||||
default:
|
||||
userMessage = `Génère une synthèse macro hebdomadaire pour ${currency} basée sur ces données :
|
||||
@@ -109,7 +144,7 @@ Résumé en 3 points : situation actuelle, signal directionnel, risque principal
|
||||
{ role: "system", content: SYSTEM_PROMPT },
|
||||
{ role: "user", content: userMessage },
|
||||
],
|
||||
max_tokens: 300,
|
||||
max_tokens: mode === "report_highlights" ? 500 : 300,
|
||||
temperature: 0.3,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user