"use client"; import React, { useState } from "react"; import { useGridStore } from "@/features/grid/store/use-grid-store"; import { useAiCopilotStore } from "@/features/ai-copilot/store/use-ai-copilot-store"; import { Sparkles, Loader2, CheckCircle2 } from "lucide-react"; import { ProductRow } from "@/types/grid"; export function BulkAiAnalyzer() { const [isAnalyzing, setIsAnalyzing] = useState(false); const [progress, setProgress] = useState({ current: 0, total: 0, message: "", errors: 0 }); const setDraftGamme = useGridStore(state => state.setDraftGamme); const setInsight = useAiCopilotStore(state => state.setInsight); const handleAnalyze = async () => { const { rows } = useGridStore.getState(); console.log("[BulkAiAnalyzer] Starting analysis on", rows.length, "rows"); setIsAnalyzing(true); try { // Group by Nomenclature (libelle3 or a fallback) const groups: Record = {}; rows.forEach(r => { const rayon = r.libelle3 || "Non classifié"; if (!groups[rayon]) groups[rayon] = []; groups[rayon].push(r); }); // Create chunks of up to 50 products per rayon const CHUNK_SIZE = 50; const chunks: { rayon: string; items: ProductRow[] }[] = []; for (const [rayon, items] of Object.entries(groups)) { for (let i = 0; i < items.length; i += CHUNK_SIZE) { chunks.push({ rayon, items: items.slice(i, i + CHUNK_SIZE) }); } } setProgress({ current: 0, total: chunks.length, message: "Initialisation...", errors: 0 }); // Process sequentially let completed = 0; for (const chunk of chunks) { setProgress(prev => ({ ...prev, current: completed, total: chunks.length, message: `Analyse du rayon: ${chunk.rayon}` })); // Simplify payload to save tokens const payloadProducts = chunk.items.map(r => ({ codein: r.codein, gtin: r.gtin, nom: r.libelle1, ventes: r.totalQuantite, marge: r.totalMarge ? parseFloat(((r.totalMarge / (r.totalCa || 1)) * 100).toFixed(1)) : 0, })); const res = await fetch("/api/ai/batch-analyze", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ rayon: chunk.rayon, products: payloadProducts }) }); if (!res.ok) { const errText = await res.text(); console.error(`[BulkAiAnalyzer] Erreur HTTP ${res.status} sur le lot ${chunk.rayon}:`, errText); setProgress(prev => ({ ...prev, errors: prev.errors + 1 })); completed++; continue; } try { const data = await res.json(); console.log(`[BulkAiAnalyzer] Response for ${chunk.rayon}:`, data); if (data && Array.isArray(data.results)) { let applied = 0; data.results.forEach((reco: any) => { if (reco.codein && reco.recommandationGamme) { setDraftGamme(reco.codein, reco.recommandationGamme); const baseJustification = reco.justificationCourte || "Aucune explication."; const justification = `Gamme ${reco.recommandationGamme} — ${baseJustification}`; setInsight(reco.codein, justification, reco.isDuplicate ?? false); applied++; } }); console.log(`[BulkAiAnalyzer] Applied ${applied} recommendations for ${chunk.rayon}`); } else { console.warn(`[BulkAiAnalyzer] Unexpected response shape for ${chunk.rayon}:`, data); } } catch (e) { console.error(`[BulkAiAnalyzer] Failed to parse JSON for chunk ${chunk.rayon}:`, e); } completed++; } setProgress(prev => ({ ...prev, current: completed, total: chunks.length, message: `Analyse terminée ! (${prev.errors > 0 ? prev.errors + " erreurs" : "succès"})` })); setTimeout(() => { setIsAnalyzing(false); }, 3000); } catch (error) { console.error("Erreur globale lors de l'analyse:", error); alert("Une erreur inattendue s'est produite pendant l'analyse globale."); setIsAnalyzing(false); } }; if (isAnalyzing) { return (
{progress.message}
); } if (progress.current === progress.total && progress.total > 0 && !isAnalyzing) { return (
Analyse terminée ({progress.total} lots analysés)
); } return ( ); }