diff --git a/src/components/ScanAndTasteFlow.tsx b/src/components/ScanAndTasteFlow.tsx
index 7a3a017..ba51f70 100644
--- a/src/components/ScanAndTasteFlow.tsx
+++ b/src/components/ScanAndTasteFlow.tsx
@@ -35,7 +35,14 @@ export default function ScanAndTasteFlow({ isOpen, onClose, imageFile }: ScanAnd
const { locale } = useI18n();
const supabase = createClient();
const [isAdmin, setIsAdmin] = useState(false);
- const [perfMetrics, setPerfMetrics] = useState<{ comp: number; ai: number; prep: number } | null>(null);
+ const [perfMetrics, setPerfMetrics] = useState<{
+ comp: number;
+ aiTotal: number;
+ aiApi: number;
+ aiParse: number;
+ uploadSize: number;
+ prep: number
+ } | null>(null);
// Admin Check
useEffect(() => {
@@ -107,7 +114,10 @@ export default function ScanAndTasteFlow({ isOpen, onClose, imageFile }: ScanAnd
if (isAdmin) {
setPerfMetrics({
comp: endComp - startComp,
- ai: endAi - startAi,
+ aiTotal: endAi - startAi,
+ aiApi: result.perf?.apiDuration || 0,
+ aiParse: result.perf?.parseDuration || 0,
+ uploadSize: result.perf?.uploadSize || 0,
prep: endPrep - startPrep
});
}
@@ -228,18 +238,32 @@ export default function ScanAndTasteFlow({ isOpen, onClose, imageFile }: ScanAnd
{isAdmin && perfMetrics && (
-
-
+
+
-
Comp
+
Client
{perfMetrics.comp.toFixed(0)}ms
+
{(perfMetrics.uploadSize / 1024).toFixed(0)} KB
-
AI
-
{perfMetrics.ai.toFixed(0)}ms
+
AI Engine
+ {perfMetrics.aiApi === 0 ? (
+
+
CACHE HIT
+
DB RESULTS
+
+ ) : (
+ <>
+
{perfMetrics.aiTotal.toFixed(0)}ms
+
+ API: {perfMetrics.aiApi.toFixed(0)}ms
+ Parse: {perfMetrics.aiParse.toFixed(0)}ms
+
+ >
+ )}
-
Prep
+
App Logic
{perfMetrics.prep.toFixed(0)}ms
@@ -289,14 +313,29 @@ export default function ScanAndTasteFlow({ isOpen, onClose, imageFile }: ScanAnd
activeSessionId={activeSession?.id}
/>
{isAdmin && perfMetrics && (
-
-
-
-
Comp: {perfMetrics.comp.toFixed(0)}ms
-
|
-
AI: {perfMetrics.ai.toFixed(0)}ms
-
|
-
Prep: {perfMetrics.prep.toFixed(0)}ms
+
+
+
+
+ CLIENT:
+ {perfMetrics.comp.toFixed(0)}ms
+ ({(perfMetrics.uploadSize / 1024).toFixed(0)}KB)
+
+
+ AI:
+ {perfMetrics.aiApi === 0 ? (
+ CACHE HIT ⚡
+ ) : (
+ <>
+ {perfMetrics.aiTotal.toFixed(0)}ms
+ (API: {perfMetrics.aiApi.toFixed(0)}ms / Pars: {perfMetrics.aiParse.toFixed(0)}ms)
+ >
+ )}
+
+
+ APP:
+ {perfMetrics.prep.toFixed(0)}ms
+
)}
diff --git a/src/services/analyze-bottle-mistral.ts b/src/services/analyze-bottle-mistral.ts
index a4c4397..e912976 100644
--- a/src/services/analyze-bottle-mistral.ts
+++ b/src/services/analyze-bottle-mistral.ts
@@ -68,6 +68,11 @@ export async function analyzeBottleMistral(input: any): Promise
0 ? tags.join(', ') : 'Keine Tags verfügbar', locale);
+ const startApi = performance.now();
const chatResponse = await client.chat.complete({
model: 'mistral-large-latest',
messages: [
@@ -93,7 +100,9 @@ export async function analyzeBottleMistral(input: any): Promise {
// 4. Hash für Cache erstellen (direkt vom Buffer -> sehr schnell)
const imageHash = createHash('sha256').update(buffer).digest('hex');
-
// Cache Check
const { data: cachedResult } = await supabase
.from('vision_cache')
@@ -69,7 +68,15 @@ export async function analyzeBottle(input: any): Promise {
.maybeSingle();
if (cachedResult) {
- return { success: true, data: cachedResult.result as any };
+ return {
+ success: true,
+ data: cachedResult.result as any,
+ perf: {
+ apiDuration: 0,
+ parseDuration: 0,
+ uploadSize: buffer.length
+ }
+ };
}
// 5. Für Gemini vorbereiten
@@ -77,10 +84,12 @@ export async function analyzeBottle(input: any): Promise {
// extrem effizient. Das Problem vorher war der JSON Parser von Next.js.
const base64Data = buffer.toString('base64');
const mimeType = file.type || 'image/webp'; // Fallback
+ const uploadSize = buffer.length;
const instruction = getSystemPrompt(tags.length > 0 ? tags.join(', ') : 'No tags available', locale);
// API Call
+ const startApi = performance.now();
const result = await geminiModel.generateContent([
{
inlineData: {
@@ -90,7 +99,9 @@ export async function analyzeBottle(input: any): Promise {
},
{ text: instruction },
]);
+ const endApi = performance.now();
+ const startParse = performance.now();
const responseText = result.response.text();
// JSON Parsing der ANTWORT (das ist klein, das schafft der N100 locker)
@@ -111,6 +122,7 @@ export async function analyzeBottle(input: any): Promise {
if (!jsonData) throw new Error('Keine Daten in der KI-Antwort gefunden.');
const validatedData = BottleMetadataSchema.parse(jsonData);
+ const endParse = performance.now();
// 6. Tracking & Credits (bleibt gleich)
await trackApiUsage({
@@ -132,7 +144,12 @@ export async function analyzeBottle(input: any): Promise {
return {
success: true,
data: validatedData,
- search_string: searchString
+ search_string: searchString,
+ perf: {
+ apiDuration: endApi - startApi,
+ parseDuration: endParse - startParse,
+ uploadSize: uploadSize
+ }
} as any;
} catch (error) {
diff --git a/src/services/magic-scan.ts b/src/services/magic-scan.ts
index 5036f05..dd07eee 100644
--- a/src/services/magic-scan.ts
+++ b/src/services/magic-scan.ts
@@ -79,7 +79,8 @@ export async function magicScan(input: any): Promise