feat: Implement bulk AI product analysis, including prompt generation, insight processing, and a dedicated UI component.

This commit is contained in:
Michael committed 2026-02-25 10:28:18 +01:00
1 parent f824476e0b
commit 0226585d4e
2 files changed
+22 -2

No files matched your search

@@ -19,7 +19,9 @@ Le score (0 à 100) est une mesure de performance RELATIVE au sein du rayon.
4. CONCISE : 2 phrases maximum. Pas de blabla technique sur les percentiles, parle de "performance relative".
--- FORMAT ATTENDU ---
"[Recommandation] : [Justification factuelle incluant le Score et les axes clés]"`;
"[Recommandation] : [Justification factuelle incluant le Score et les axes clés]"
Exemple : "[A] : Score de 85/100 porté par une marge excellente de 45% et une forte croissance volume."
Exemple : "[Z] : Score faible (12/100) en raison d'une baisse drastique du CA et d'une inactivité de 3 mois."`;
}
static generateUserMessage(p: ProductAnalysisInput): string {
@@ -3,6 +3,7 @@
import React, { useState, useRef } from "react";
import { useGridStore } from "@/features/grid/store/use-grid-store";
import { useAiCopilotStore } from "@/features/ai-copilot/store/use-ai-copilot-store";
import { ScoringEngine } from "@/features/ai-copilot/business/scoring-engine";
import { Sparkles, Loader2, CheckCircle2, XCircle } from "lucide-react";
import { ProductRow, GammeCode } from "@/types/grid";
import { ProductAnalysisInput } from "@/features/ai-copilot/models/ai-analysis.types";
@@ -55,7 +56,7 @@ export function BulkAiAnalyzer() {
}
});
const productPayloads: ProductAnalysisInput[] = rows.map((r) => {
const initialPayloads: ProductAnalysisInput[] = rows.map((r) => {
const sc = r.workingStores?.length || 1;
const weight = sc === 1 ? 2 : 1;
const rb = rayonBenchmarks.get(r.libelleNiveau2 || "Général");
@@ -105,6 +106,23 @@ export function BulkAiAnalyzer() {
};
});
// 2. Calculer le scoring algorithmique pour chaque produit
const productPayloads = initialPayloads.map(p => {
const scoringRes = ScoringEngine.analyzeRayon(p, initialPayloads);
return {
...p,
scoring: {
compositeScore: scoringRes.compositeScore,
decision: scoringRes.decision.recommendation,
labelProfil: scoringRes.decision.labelProfil,
isTop30Supplier: scoringRes.decision.isTop30Supplier,
isRecent: scoringRes.decision.isRecent,
isLastProduct: scoringRes.decision.isLastProduct,
threshold: scoringRes.decision.threshold,
}
};
});
setIsAnalyzing(true);
let completed = 0;
let errorsCount = 0;