mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-21 22:18:08 +02:00
feat: Add bulk AI analyzer component to process product data and generate insights.
This commit is contained in:
1 parent
8c02771e46
commit
17498dcc10
4 files changed
+47
-8
No files matched your search
@@ -12,15 +12,18 @@ interface AiInsightBlockProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function AiInsightBlock({ row }: AiInsightBlockProps) {
|
export function AiInsightBlock({ row }: AiInsightBlockProps) {
|
||||||
const { insights, analyzeProduct } = useAiCopilotStore();
|
const insight = useAiCopilotStore((s) => s.insights[row.codein]);
|
||||||
const setDraftGamme = useGridStore(state => state.setDraftGamme);
|
const analyzeProduct = useAiCopilotStore((s) => s.analyzeProduct);
|
||||||
const insight = insights[row.codein];
|
const setLoading = useAiCopilotStore((s) => s.setLoading);
|
||||||
|
const setDraftGamme = useGridStore((s) => s.setDraftGamme);
|
||||||
|
|
||||||
const status = insight?.status ?? "idle";
|
const status = insight?.status ?? "idle";
|
||||||
|
|
||||||
const handleAnalyze = () => {
|
const handleAnalyze = () => {
|
||||||
if (status === "loading") return;
|
if (status === "loading") return;
|
||||||
|
|
||||||
// Vider la recommandation actuelle avant de relancer l'IA
|
// Reset Visuel Immédiat
|
||||||
|
setLoading(row.codein);
|
||||||
setDraftGamme(row.codein, "Aucune");
|
setDraftGamme(row.codein, "Aucune");
|
||||||
|
|
||||||
const regScore = Object.values(row.sales12m || {}).filter(v => v > 0).length;
|
const regScore = Object.values(row.sales12m || {}).filter(v => v > 0).length;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ interface AiCopilotState {
|
|||||||
insights: Record<string, AiInsight>;
|
insights: Record<string, AiInsight>;
|
||||||
setInsight: (codein: string, insight: string, isDuplicate?: boolean) => void;
|
setInsight: (codein: string, insight: string, isDuplicate?: boolean) => void;
|
||||||
setLoading: (codein: string) => void;
|
setLoading: (codein: string) => void;
|
||||||
|
batchSetLoading: (codeins: string[]) => void;
|
||||||
setError: (codein: string, error: string) => void;
|
setError: (codein: string, error: string) => void;
|
||||||
analyzeProduct: (payload: {
|
analyzeProduct: (payload: {
|
||||||
codein: string;
|
codein: string;
|
||||||
@@ -56,6 +57,16 @@ export const useAiCopilotStore = create<AiCopilotState>()(
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
batchSetLoading: (codeins) => {
|
||||||
|
set((s) => {
|
||||||
|
const nextInsights = { ...s.insights };
|
||||||
|
codeins.forEach(codein => {
|
||||||
|
nextInsights[codein] = { codein, insight: "", status: "loading" };
|
||||||
|
});
|
||||||
|
return { insights: nextInsights };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
setError: (codein, error) => {
|
setError: (codein, error) => {
|
||||||
set((s) => ({
|
set((s) => ({
|
||||||
insights: {
|
insights: {
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ export function BulkAiAnalyzer() {
|
|||||||
const [progress, setProgress] = useState({ current: 0, total: 0, message: "", errors: 0 });
|
const [progress, setProgress] = useState({ current: 0, total: 0, message: "", errors: 0 });
|
||||||
const isCancelledRef = useRef(false);
|
const isCancelledRef = useRef(false);
|
||||||
|
|
||||||
|
const batchSetDraftGamme = useGridStore((s) => s.batchSetDraftGamme);
|
||||||
const setDraftGamme = useGridStore((s) => s.setDraftGamme);
|
const setDraftGamme = useGridStore((s) => s.setDraftGamme);
|
||||||
const { setInsight, setLoading, setError } = useAiCopilotStore();
|
const { setInsight, batchSetLoading, setError } = useAiCopilotStore();
|
||||||
|
|
||||||
const handleStop = () => {
|
const handleStop = () => {
|
||||||
isCancelledRef.current = true;
|
isCancelledRef.current = true;
|
||||||
@@ -111,6 +112,14 @@ export function BulkAiAnalyzer() {
|
|||||||
const totalItems = productPayloads.length;
|
const totalItems = productPayloads.length;
|
||||||
setProgress({ current: 0, total: totalItems, message: "Initialisation...", errors: 0 });
|
setProgress({ current: 0, total: totalItems, message: "Initialisation...", errors: 0 });
|
||||||
|
|
||||||
|
// Reset global ATOMIQUE et IMMÉDIAT
|
||||||
|
const codeins = productPayloads.map(p => p.codein);
|
||||||
|
batchSetLoading(codeins);
|
||||||
|
|
||||||
|
const gammeChanges: Record<string, GammeCode> = {};
|
||||||
|
codeins.forEach(c => gammeChanges[c] = "Aucune");
|
||||||
|
batchSetDraftGamme(gammeChanges);
|
||||||
|
|
||||||
const CONCURRENCY = 3;
|
const CONCURRENCY = 3;
|
||||||
const remaining = [...productPayloads];
|
const remaining = [...productPayloads];
|
||||||
|
|
||||||
@@ -120,9 +129,6 @@ export function BulkAiAnalyzer() {
|
|||||||
const payload = remaining.shift();
|
const payload = remaining.shift();
|
||||||
if (!payload) break;
|
if (!payload) break;
|
||||||
|
|
||||||
setLoading(payload.codein);
|
|
||||||
setDraftGamme(payload.codein, "Aucune");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let res: Response | null = null;
|
let res: Response | null = null;
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ interface GridState {
|
|||||||
setDisplayDensity: (density: "compact" | "normal" | "comfortable") => void;
|
setDisplayDensity: (density: "compact" | "normal" | "comfortable") => void;
|
||||||
setActiveGridQuery: (query: string) => void;
|
setActiveGridQuery: (query: string) => void;
|
||||||
restoreSnapshot: (changes: Record<string, GammeCode>) => void;
|
restoreSnapshot: (changes: Record<string, GammeCode>) => void;
|
||||||
|
batchSetDraftGamme: (changes: Record<string, GammeCode>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeSummary(rows: ProductRow[], drafts: Record<string, GammeCode>): GridSummary {
|
function computeSummary(rows: ProductRow[], drafts: Record<string, GammeCode>): GridSummary {
|
||||||
@@ -105,6 +106,24 @@ export const useGridStore = create<GridState>()(
|
|||||||
restoreSnapshot: (changes) => {
|
restoreSnapshot: (changes) => {
|
||||||
set({ draftChanges: changes, summary: computeSummary(get().rows, changes) });
|
set({ draftChanges: changes, summary: computeSummary(get().rows, changes) });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
batchSetDraftGamme: (newChanges) => {
|
||||||
|
const { rows, draftChanges: oldDrafts } = get();
|
||||||
|
const updatedDrafts = { ...oldDrafts };
|
||||||
|
|
||||||
|
Object.entries(newChanges).forEach(([codein, gamme]) => {
|
||||||
|
const originalRow = rows.find(r => r.codein === codein);
|
||||||
|
const originalGamme = originalRow?.codeGamme;
|
||||||
|
|
||||||
|
if (gamme === originalGamme) {
|
||||||
|
delete updatedDrafts[codein];
|
||||||
|
} else {
|
||||||
|
updatedDrafts[codein] = gamme;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
set({ draftChanges: updatedDrafts, summary: computeSummary(rows, updatedDrafts) });
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "collectflow-grid-storage",
|
name: "collectflow-grid-storage",
|
||||||
|
|||||||
Reference in new issue
Block a user