mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-11 17:26:32 +02:00
feat: Add bulk AI product analysis component with supporting data types and AI system prompt.
This commit is contained in:
1 parent
b015d1f093
commit
661704bf38
3 files changed
+16
-4
No files matched your search
@@ -13,7 +13,8 @@ Critères de pondération et Règles Métier :
|
||||
1. Volume Relatif (Flux de stock) : Si le volume est élevé (très supérieur à la moyenne), c'est un produit "fond de rayon" qui génère du trafic. ON LE GARDE (A ou C) même si son CA individuel est faible.
|
||||
2. Mix CA/Marge (Rentabilité) : Si le volume est faible mais que le produit génère un CA conséquent et une BONNE MARGE, c'est une pépite. ON LE GARDE EN A.
|
||||
3. Poids Relatif : Analyse toujours la performance du produit PAR RAPPORT AU RESTE (moyenne fournisseur). Un produit doit être Z uniquement s'il est faible sur TOUS les indicateurs (Volume, CA, Marge).
|
||||
4. Régularité : La stabilité sur 12 mois est la signature du Permanent (A).
|
||||
4. Contexte Magasins (Crucial) : Compare le produit à ses pairs. Si le produit est dans 1 magasin, compare son volume à la moyenne des produits à 1 magasin (avgQtyGroup1). Ne le pénalise pas parce qu'il vend moins qu'un produit présent dans 2 magasins ou plus. Un produit à 1 magasin qui performe mieux que la moyenne de son groupe est un excellent candidat A.
|
||||
5. Régularité : La stabilité sur 12 mois est la signature du Permanent (A).
|
||||
|
||||
Ta réponse doit être en 1-2 phrases maximum, en français, directe et actionnable.
|
||||
Format impératif : "[Recommandation]: [Justification courte]"`;
|
||||
@@ -30,6 +31,7 @@ Format impératif : "[Recommandation]: [Justification courte]"`;
|
||||
|
||||
return `Produit : "${p.libelle1}" (Ref: ${p.codein})
|
||||
Gamme actuelle : ${p.codeGamme ?? "Non définie"}
|
||||
Contexte : Données basées sur ${p.storeCount} magasin(s).
|
||||
Indicateurs 12m :
|
||||
- CA : ${p.totalCa.toFixed(2)}€
|
||||
- Marge : ${p.tauxMarge.toFixed(1)}%
|
||||
|
||||
@@ -5,6 +5,9 @@ export interface ProductAnalysisInput {
|
||||
tauxMarge: number;
|
||||
totalQuantite: number;
|
||||
avgTotalQuantite?: number;
|
||||
avgQtyGroup1?: number; // Moyenne volume pour produits à 1 magasin
|
||||
avgQtyGroup2?: number; // Moyenne volume pour produits à 2 magasins+
|
||||
storeCount: number;
|
||||
sales12m: Record<string, number>;
|
||||
codeGamme: string | null;
|
||||
}
|
||||
|
||||
@@ -20,12 +20,16 @@ export function BulkAiAnalyzer() {
|
||||
};
|
||||
|
||||
const handleAnalyze = async () => {
|
||||
const { rows } = useGridStore.getState();
|
||||
isCancelledRef.current = false;
|
||||
|
||||
const totalQtySum = rows.reduce((sum, r) => sum + (r.totalQuantite || 0), 0);
|
||||
const avgQty = rows.length > 0 ? totalQtySum / rows.length : 0;
|
||||
|
||||
// Benchmarks par groupe de magasins
|
||||
const rowsGroup1 = rows.filter(r => (r.workingStores?.length || 1) === 1);
|
||||
const rowsGroup2 = rows.filter(r => (r.workingStores?.length || 1) >= 2);
|
||||
|
||||
const avgQty1 = rowsGroup1.length > 0 ? rowsGroup1.reduce((s, r) => s + (r.totalQuantite || 0), 0) / rowsGroup1.length : 0;
|
||||
const avgQty2 = rowsGroup2.length > 0 ? rowsGroup2.reduce((s, r) => s + (r.totalQuantite || 0), 0) / rowsGroup2.length : 0;
|
||||
|
||||
const productPayloads: ProductAnalysisInput[] = rows.map(r => ({
|
||||
codein: r.codein,
|
||||
libelle1: r.libelle1 || "",
|
||||
@@ -33,6 +37,9 @@ export function BulkAiAnalyzer() {
|
||||
tauxMarge: r.tauxMarge || 0,
|
||||
totalQuantite: r.totalQuantite || 0,
|
||||
avgTotalQuantite: avgQty,
|
||||
avgQtyGroup1: avgQty1,
|
||||
avgQtyGroup2: avgQty2,
|
||||
storeCount: r.workingStores?.length || 1,
|
||||
sales12m: r.sales12m || {},
|
||||
codeGamme: r.codeGamme || null,
|
||||
}));
|
||||
|
||||
Reference in new issue
Block a user