feat: Switch to Mistral Large 3 (mistral-large-latest)
This commit is contained in:
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/types/routes.d.ts";
|
import "./.next/dev/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export default function CameraCapture({ onImageCaptured, onAnalysisComplete, onS
|
|||||||
const [isDiscovering, setIsDiscovering] = useState(false);
|
const [isDiscovering, setIsDiscovering] = useState(false);
|
||||||
const [originalFile, setOriginalFile] = useState<File | null>(null);
|
const [originalFile, setOriginalFile] = useState<File | null>(null);
|
||||||
const [isAdmin, setIsAdmin] = useState(false);
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
const [aiProvider, setAiProvider] = useState<'gemini' | 'pixtral'>('gemini');
|
const [aiProvider, setAiProvider] = useState<'gemini' | 'mistral'>('gemini');
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const checkAdmin = async () => {
|
const checkAdmin = async () => {
|
||||||
@@ -364,10 +364,10 @@ export default function CameraCapture({ onImageCaptured, onAnalysisComplete, onS
|
|||||||
Gemini
|
Gemini
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setAiProvider('pixtral')}
|
onClick={() => setAiProvider('mistral')}
|
||||||
className={`px-3 py-1 text-[10px] font-black uppercase tracking-widest rounded-lg transition-all ${aiProvider === 'pixtral' ? 'bg-white dark:bg-zinc-700 text-amber-600 shadow-sm' : 'text-zinc-400'}`}
|
className={`px-3 py-1 text-[10px] font-black uppercase tracking-widest rounded-lg transition-all ${aiProvider === 'mistral' ? 'bg-white dark:bg-zinc-700 text-amber-600 shadow-sm' : 'text-zinc-400'}`}
|
||||||
>
|
>
|
||||||
Pixtral 🇪🇺
|
Mistral 3 🇪🇺
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export interface PendingScan {
|
|||||||
temp_id: string; // Used to link tasting notes before sync
|
temp_id: string; // Used to link tasting notes before sync
|
||||||
imageBase64: string;
|
imageBase64: string;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
provider?: 'gemini' | 'pixtral';
|
provider?: 'gemini' | 'mistral';
|
||||||
locale?: string;
|
locale?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { createHash } from 'crypto';
|
|||||||
import { trackApiUsage } from './track-api-usage';
|
import { trackApiUsage } from './track-api-usage';
|
||||||
import { checkCreditBalance, deductCredits } from './credit-service';
|
import { checkCreditBalance, deductCredits } from './credit-service';
|
||||||
|
|
||||||
export async function analyzeBottlePixtral(base64Image: string, tags?: string[], locale: string = 'de'): Promise<AnalysisResponse & { search_string?: string }> {
|
export async function analyzeBottleMistral(base64Image: string, tags?: string[], locale: string = 'de'): Promise<AnalysisResponse & { search_string?: string }> {
|
||||||
if (!process.env.MISTRAL_API_KEY) {
|
if (!process.env.MISTRAL_API_KEY) {
|
||||||
return { success: false, error: 'MISTRAL_API_KEY is not configured.' };
|
return { success: false, error: 'MISTRAL_API_KEY is not configured.' };
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ Antworte AUSSCHLIESSLICH mit gültigem JSON (kein Markdown, kein Text davor/dana
|
|||||||
}`;
|
}`;
|
||||||
|
|
||||||
const chatResponse = await client.chat.complete({
|
const chatResponse = await client.chat.complete({
|
||||||
model: 'pixtral-large-latest',
|
model: 'mistral-large-latest',
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
@@ -81,7 +81,7 @@ Antworte AUSSCHLIESSLICH mit gültigem JSON (kein Markdown, kein Text davor/dana
|
|||||||
});
|
});
|
||||||
|
|
||||||
const rawContent = chatResponse.choices?.[0].message.content;
|
const rawContent = chatResponse.choices?.[0].message.content;
|
||||||
if (!rawContent) throw new Error("Keine Antwort von Pixtral");
|
if (!rawContent) throw new Error("Keine Antwort von Mistral");
|
||||||
|
|
||||||
const jsonData = JSON.parse(rawContent as string);
|
const jsonData = JSON.parse(rawContent as string);
|
||||||
|
|
||||||
@@ -104,12 +104,12 @@ Antworte AUSSCHLIESSLICH mit gültigem JSON (kein Markdown, kein Text davor/dana
|
|||||||
await trackApiUsage({
|
await trackApiUsage({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
apiType: 'gemini_ai', // Keep as generic 'gemini_ai' for now or update schema later
|
apiType: 'gemini_ai', // Keep as generic 'gemini_ai' for now or update schema later
|
||||||
endpoint: 'mistral/pixtral-large',
|
endpoint: 'mistral/mistral-large',
|
||||||
success: true
|
success: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Deduct credits
|
// Deduct credits
|
||||||
await deductCredits(userId, 'gemini_ai', 'Pixtral AI analysis');
|
await deductCredits(userId, 'gemini_ai', 'Mistral AI analysis');
|
||||||
|
|
||||||
// Store in Cache
|
// Store in Cache
|
||||||
await supabase
|
await supabase
|
||||||
@@ -123,7 +123,7 @@ Antworte AUSSCHLIESSLICH mit gültigem JSON (kein Markdown, kein Text davor/dana
|
|||||||
};
|
};
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Pixtral Analysis Error:', error);
|
console.error('Mistral Analysis Error:', error);
|
||||||
|
|
||||||
// Track failed API call
|
// Track failed API call
|
||||||
try {
|
try {
|
||||||
@@ -133,7 +133,7 @@ Antworte AUSSCHLIESSLICH mit gültigem JSON (kein Markdown, kein Text davor/dana
|
|||||||
await trackApiUsage({
|
await trackApiUsage({
|
||||||
userId: session.user.id,
|
userId: session.user.id,
|
||||||
apiType: 'gemini_ai',
|
apiType: 'gemini_ai',
|
||||||
endpoint: 'mistral/pixtral-large',
|
endpoint: 'mistral/mistral-large',
|
||||||
success: false,
|
success: false,
|
||||||
errorMessage: error instanceof Error ? error.message : 'Unknown error'
|
errorMessage: error instanceof Error ? error.message : 'Unknown error'
|
||||||
});
|
});
|
||||||
@@ -145,7 +145,7 @@ Antworte AUSSCHLIESSLICH mit gültigem JSON (kein Markdown, kein Text davor/dana
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error instanceof Error ? error.message : 'Pixtral AI analysis failed.',
|
error: error instanceof Error ? error.message : 'Mistral AI analysis failed.',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
'use server';
|
'use server';
|
||||||
|
|
||||||
import { analyzeBottle } from './analyze-bottle';
|
import { analyzeBottle } from './analyze-bottle';
|
||||||
import { analyzeBottlePixtral } from './analyze-bottle-pixtral';
|
import { analyzeBottleMistral } from './analyze-bottle-mistral';
|
||||||
import { searchBraveForWhiskybase } from './brave-search';
|
import { searchBraveForWhiskybase } from './brave-search';
|
||||||
import { getAllSystemTags } from './tags';
|
import { getAllSystemTags } from './tags';
|
||||||
import { supabase } from '@/lib/supabase';
|
import { supabase } from '@/lib/supabase';
|
||||||
import { supabaseAdmin } from '@/lib/supabase-admin';
|
import { supabaseAdmin } from '@/lib/supabase-admin';
|
||||||
import { AnalysisResponse, BottleMetadata } from '@/types/whisky';
|
import { AnalysisResponse, BottleMetadata } from '@/types/whisky';
|
||||||
|
|
||||||
export async function magicScan(base64Image: string, provider: 'gemini' | 'pixtral' = 'gemini', locale: string = 'de'): Promise<AnalysisResponse & { wb_id?: string }> {
|
export async function magicScan(base64Image: string, provider: 'gemini' | 'mistral' = 'gemini', locale: string = 'de'): Promise<AnalysisResponse & { wb_id?: string }> {
|
||||||
try {
|
try {
|
||||||
console.log('[magicScan] Starting scan process...');
|
console.log('[magicScan] Starting scan process...');
|
||||||
if (!supabase) {
|
if (!supabase) {
|
||||||
@@ -22,8 +22,8 @@ export async function magicScan(base64Image: string, provider: 'gemini' | 'pixtr
|
|||||||
|
|
||||||
// 1. AI Analysis
|
// 1. AI Analysis
|
||||||
let aiResponse: any;
|
let aiResponse: any;
|
||||||
if (provider === 'pixtral') {
|
if (provider === 'mistral') {
|
||||||
aiResponse = await analyzeBottlePixtral(base64Image, tagNames, locale);
|
aiResponse = await analyzeBottleMistral(base64Image, tagNames, locale);
|
||||||
} else {
|
} else {
|
||||||
aiResponse = await analyzeBottle(base64Image, tagNames, locale);
|
aiResponse = await analyzeBottle(base64Image, tagNames, locale);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user