feat: implement AI product analysis endpoint using OpenRouter with optimized timeout handling and N+1 query prevention.

This commit is contained in:
Michael committed 2026-02-27 10:36:34 +01:00
1 parent 51a30b26e4
commit 02fdd18a52
3 files changed
+10 -21

No files matched your search

+3 -17
View File
@@ -2,9 +2,6 @@ import { NextRequest, NextResponse } from "next/server";
import { getSavedDatabaseConfig } from "@/features/settings/actions";
import { OpenRouterClient } from "@/features/ai-copilot/data/open-router-client";
import { ProductAnalysisInput } from "@/features/ai-copilot/models/ai-analysis.types";
import { db } from "@/db";
import { aiSupplierContext } from "@/db/schema";
import { eq } from "drizzle-orm";
// Limite max acceptable pour la route (Node.js self-hosted).
// Evite que le process tourne indéfiniment en cas de deadlock.
@@ -23,20 +20,9 @@ export async function POST(req: NextRequest) {
try {
const body: ProductAnalysisInput = await req.json();
// Inject supplier context if available
if (body.codeFournisseur) {
try {
const contextRecord = await db.select()
.from(aiSupplierContext)
.where(eq(aiSupplierContext.codeFournisseur, body.codeFournisseur))
.limit(1);
if (contextRecord.length > 0 && contextRecord[0].context) {
body.supplierContext = contextRecord[0].context;
}
} catch (err) {
console.error("[AI] Failed to fetch supplier context:", err);
}
}
// Le supplierContext est déjà injecté par le client (BulkAiAnalyzer)
// via une requête unique avant de lancer le batch.
// Cela nous évite une requête DB N+1 pour chaque produit analysé.
const client = new OpenRouterClient({ apiKey, model });
const result = await client.analyzeProduct(body);
@@ -12,10 +12,10 @@ export class OpenRouterClient {
constructor(private config: OpenRouterConfig) { }
async analyzeProduct(p: ProductAnalysisInput): Promise<AnalysisResult> {
// Timeout de 25 secondes : évite le blocage indéfini si OpenRouter est lent.
// On préfère un échec propre avec message d'erreur plutôt qu'un timeout navigateur.
// Timeout de 50 secondes : évite le blocage indéfini si OpenRouter est lent,
// tout en laissant assez de temps aux modèles complexes pour répondre (maxDuration serveur = 55s).
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 25_000);
const timeoutId = setTimeout(() => controller.abort(), 50_000);
let response: Response;
try {
+4 -1
View File
@@ -25,4 +25,7 @@ Mary (IA) donnait des recommandations basées sur le score brut sans analyse con
- **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.
- **Vérification** : Walkthrough documenté.
- **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.
- **Vérification** : Walkthrough documenté et système fluidifié.