mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-11 17:26:32 +02:00
feat: Implement bulk AI product analysis, including algorithmic scoring and context profiling, with a new OpenRouter client.
This commit is contained in:
1 parent
02fdd18a52
commit
b0bb8cc09a
4 files changed
+24
-19
No files matched your search
@@ -17,7 +17,8 @@ export class AnalysisEngine {
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
static generateSystemPrompt(): string {
|
||||
return `Tu es Mary, Senior Retail Strategist. Tu analyses des produits pour recommander A (garder), C (saisonnier), ou Z (sortir).
|
||||
return `Tu es Mary, Senior Retail Strategist. Tu analyses des produits pour recommander A (garder) ou Z (sortir).
|
||||
IMPORTANT : La gamme C est RÉSERVÉE aux produits saisonniers et gérée MANUELLEMENT par l'acheteur. Tu ne dois JAMAIS recommander C.
|
||||
|
||||
--- ORDRE DE PRIORITÉ (STRICT) ---
|
||||
|
||||
@@ -27,21 +28,21 @@ export class AnalysisEngine {
|
||||
Si isLowContribution = true [poids CA < 0.5% ET poids QTÉ < 0.5% du fournisseur]
|
||||
ET score composite < 35
|
||||
ET scoreCritique = true [score brut < 20]
|
||||
→ Z DIRECT. Ce produit est marginal et sous-performant. Aucun signal ne peut l'annuler.
|
||||
→ Z DIRECT. Ce produit est marginal et sous-performant.
|
||||
|
||||
3. RÈGLE MANAGER : Si le manager a défini une consigne ET que le produit est concerné → Appliquer.
|
||||
|
||||
4. ANALYSE CONTEXTUELLE (si aucune règle ci-dessus ne s'applique) :
|
||||
Utilise les données de la fiche pour raisonner. Les quadrants sont des INDICES, pas des verdicts.
|
||||
|
||||
— Quadrant STAR ⭐ : Fort signal positif. A sauf inactivité ≥ 3 mois.
|
||||
— Quadrant STAR ⭐ : Fort signal positif → A sauf inactivité ≥ 3 mois.
|
||||
— Quadrant TRAFIC 🚶 : Signal positif SEULEMENT si poids QTÉ fournisseur > 1%.
|
||||
Si poids < 1% et score < 40 → tendance Z ou C.
|
||||
Si poids < 1% et score < 40 → Z.
|
||||
— Quadrant MARGE 💎 : Signal positif SEULEMENT si poids CA fournisseur > 0.5%.
|
||||
Si poids < 0.5% et score < 35 → tendance Z.
|
||||
— Quadrant WATCH ⚠️ : Signal négatif par défaut.
|
||||
Si poids CA rayon > 5% ou poids QTÉ rayon > 5% → A ou C selon inactivité.
|
||||
Sinon → Z si inactivité ≥ 2 mois, C si 1 mois, A si actif mais surveiller.
|
||||
Si poids < 0.5% et score < 35 → Z.
|
||||
— Quadrant WATCH ⚠️ : Signal négatif.
|
||||
Si poids CA rayon > 5% ou poids QTÉ rayon > 5% → A (surveiller).
|
||||
Sinon → Z si inactivité ≥ 2 mois, A si actif.
|
||||
|
||||
--- COHÉRENCE INTER-PRODUITS ---
|
||||
Ne mets jamais Z un produit si son percentile CA ET son percentile QTÉ sont tous les deux supérieurs à un autre produit déjà classé A dans ce lot.
|
||||
@@ -50,7 +51,7 @@ Ne mets jamais Z un produit si son percentile CA ET son percentile QTÉ sont tou
|
||||
JSON uniquement, sans markdown.
|
||||
{
|
||||
"rule_applies": boolean,
|
||||
"recommendation": "A" | "C" | "Z",
|
||||
"recommendation": "A" | "Z",
|
||||
"justification": "2 phrases max. Cite poids, percentile, quadrant, score."
|
||||
}`;
|
||||
}
|
||||
@@ -181,9 +182,9 @@ Génère UNIQUEMENT le JSON :`;
|
||||
// Utilitaires de parsing (inchangés)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
static extractRecommendation(content: string): "A" | "C" | "Z" | null {
|
||||
const match = content.match(/\b([ACZ])\b/i);
|
||||
if (match) return match[1].toUpperCase() as "A" | "C" | "Z";
|
||||
static extractRecommendation(content: string): "A" | "Z" | null {
|
||||
const match = content.match(/\b([AZ])\b/i);
|
||||
if (match) return match[1].toUpperCase() as "A" | "Z";
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ export class OpenRouterClient {
|
||||
{ role: "user", content: AnalysisEngine.generateUserMessage(p) },
|
||||
],
|
||||
response_format: { type: "json_object" },
|
||||
max_tokens: 200,
|
||||
max_tokens: 150,
|
||||
temperature: 0.1,
|
||||
}),
|
||||
});
|
||||
@@ -73,8 +73,12 @@ export class OpenRouterClient {
|
||||
reco = parsed.recommendation as "A" | "C" | "Z";
|
||||
cleanInsight = parsed.justification || "";
|
||||
|
||||
// Garde-fou : C est réservé aux saisonniers (gestion manuelle).
|
||||
// Si l'IA recommande C malgré l'interdiction dans le prompt → forcer A.
|
||||
if (reco === "C") reco = "A";
|
||||
|
||||
// Override recommendation if it doesn't match extracted reco for safety
|
||||
if (!reco || !["A", "C", "Z"].includes(reco)) {
|
||||
if (!reco || !["A", "Z"].includes(reco)) {
|
||||
reco = AnalysisEngine.extractRecommendation(cleanInsight) || "A";
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -181,7 +181,7 @@ export function BulkAiAnalyzer() {
|
||||
codeins.forEach(c => gammeChanges[c] = "Aucune");
|
||||
batchSetDraftGamme(gammeChanges);
|
||||
|
||||
const CONCURRENCY = 3;
|
||||
const CONCURRENCY = 2;
|
||||
const remaining = [...productPayloads];
|
||||
|
||||
const processBatch = async () => {
|
||||
@@ -298,9 +298,9 @@ export function BulkAiAnalyzer() {
|
||||
) : (
|
||||
<button
|
||||
onClick={handleAnalyze}
|
||||
className="apple-btn-ai"
|
||||
className="apple-btn-secondary"
|
||||
>
|
||||
<Sparkles className="w-4 h-4" />
|
||||
<Sparkles className="w-4 h-4" style={{ color: "var(--accent)" }} />
|
||||
Analyse IA
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -23,9 +23,9 @@ Mary (IA) donnait des recommandations basées sur le score brut sans analyse con
|
||||
|
||||
## Progress Log
|
||||
|
||||
- **Correction IA** : Algorithme Mary v4 implémenté avec profilage contextuel et groupement N2. Le bug de classification 'A' systématique est résolu.
|
||||
- **Refonte Esthétique** : Bouton de sauvegarde et design system harmonisés en style Apple Glossy/Premium avec micro-animations et feedback visuel.
|
||||
- **Agent Architecte (Timeout)** : Intervention structurelle sur l'entonnoir d'analyse :
|
||||
- **Client-Side (AbortController)** : Timeout poussé de 25s à 50s pour supporter les requêtes des LLM denses (ex: M37).
|
||||
- **Server-Side (N+1 Query)** : Suppression d'une requête BDD redondante invoquée par chaque produit, éliminant ~100 appels BDD par lot.
|
||||
- **Agent Architecte (Gamme C)** : Prompt v5 → Mary ne recommande plus que A ou Z. Gamme C interdite (réservée saisonniers). Garde-fou C→A côté client. Concurrence réduite à 2 workers, max_tokens réduit à 150.
|
||||
- **Bouton Analyse IA** : Refactorisé en `apple-btn-secondary` (sobre, conforme PRD Apple-style) avec icône Sparkles colorée en accent.
|
||||
- **Vérification** : Walkthrough documenté et système fluidifié.
|
||||
Reference in new issue
Block a user