fix: improve server action resilience and error logging
- Moved Supabase client initialization inside try-catch in Server Actions - Added safety checks for null Supabase client in magicScan - Added detailed server-side logging for debugging deployment issues - Ensures all failure paths return a structured error response instead of 500
This commit is contained in:
@@ -10,13 +10,14 @@ import { trackApiUsage } from './track-api-usage';
|
||||
import { checkCreditBalance, deductCredits } from './credit-service';
|
||||
|
||||
export async function analyzeBottleNebius(base64Image: string, tags?: string[], locale: string = 'de'): Promise<AnalysisResponse & { search_string?: string }> {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
|
||||
if (!process.env.NEBIUS_API_KEY) {
|
||||
return { success: false, error: 'NEBIUS_API_KEY is not configured.' };
|
||||
}
|
||||
|
||||
let supabase;
|
||||
try {
|
||||
supabase = createServerActionClient({ cookies });
|
||||
console.log('[analyzeBottleNebius] Initialized Supabase client');
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (!session || !session.user) {
|
||||
return { success: false, error: 'Nicht autorisiert oder Session abgelaufen.' };
|
||||
@@ -52,6 +53,8 @@ export async function analyzeBottleNebius(base64Image: string, tags?: string[],
|
||||
.replace('{AVAILABLE_TAGS}', tags ? tags.join(', ') : 'No tags available')
|
||||
.replace('{LANGUAGE}', locale === 'en' ? 'English' : 'German')
|
||||
+ "\nAdditionally, generate a 'search_string' field for Whiskybase in this format: 'site:whiskybase.com [Distillery] [Name] [Vintage]'. Include this field in the JSON object.";
|
||||
console.log(`[analyzeBottleNebius] Instruction prepared for AI: ${instruction.substring(0, 100)}...`);
|
||||
|
||||
|
||||
const response = await aiClient.chat.completions.create({
|
||||
model: "Qwen/Qwen2.5-VL-72B-Instruct",
|
||||
@@ -116,6 +119,25 @@ export async function analyzeBottleNebius(base64Image: string, tags?: string[],
|
||||
|
||||
} catch (error) {
|
||||
console.error('Nebius Analysis Error:', error);
|
||||
|
||||
// Track failed API call
|
||||
try {
|
||||
if (supabase) {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (session?.user) {
|
||||
await trackApiUsage({
|
||||
userId: session.user.id,
|
||||
apiType: 'gemini_ai',
|
||||
endpoint: 'nebius/qwen2.5-vl',
|
||||
success: false,
|
||||
errorMessage: error instanceof Error ? error.message : 'Unknown error'
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (trackError) {
|
||||
console.error('Failed to track error:', trackError);
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Nebius AI analysis failed.',
|
||||
|
||||
@@ -9,13 +9,16 @@ import { trackApiUsage } from './track-api-usage';
|
||||
import { checkCreditBalance, deductCredits } from './credit-service';
|
||||
|
||||
export async function analyzeBottle(base64Image: string, tags?: string[], locale: string = 'de'): Promise<AnalysisResponse> {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
|
||||
if (!process.env.GEMINI_API_KEY) {
|
||||
return { success: false, error: 'GEMINI_API_KEY is not configured.' };
|
||||
}
|
||||
|
||||
let supabase; // Declare supabase outside try block for error tracking access
|
||||
try {
|
||||
// Initialize Supabase client inside the try block
|
||||
supabase = createServerActionClient({ cookies });
|
||||
console.log('[analyzeBottle] Initialized Supabase client');
|
||||
|
||||
// ... (auth and credit check remain same) ...
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (!session || !session.user) {
|
||||
@@ -110,15 +113,17 @@ export async function analyzeBottle(base64Image: string, tags?: string[], locale
|
||||
|
||||
// Track failed API call
|
||||
try {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (session?.user) {
|
||||
await trackApiUsage({
|
||||
userId: session.user.id,
|
||||
apiType: 'gemini_ai',
|
||||
endpoint: 'generateContent',
|
||||
success: false,
|
||||
errorMessage: error instanceof Error ? error.message : 'Unknown error'
|
||||
});
|
||||
if (supabase) {
|
||||
const { data: { session } } = await supabase.auth.getSession();
|
||||
if (session?.user) {
|
||||
await trackApiUsage({
|
||||
userId: session.user.id,
|
||||
apiType: 'gemini_ai',
|
||||
endpoint: 'generateContent',
|
||||
success: false,
|
||||
errorMessage: error instanceof Error ? error.message : 'Unknown error'
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (trackError) {
|
||||
console.error('Failed to track error:', trackError);
|
||||
|
||||
@@ -10,9 +10,15 @@ import { AnalysisResponse, BottleMetadata } from '@/types/whisky';
|
||||
|
||||
export async function magicScan(base64Image: string, provider: 'gemini' | 'nebius' = 'gemini', locale: string = 'de'): Promise<AnalysisResponse & { wb_id?: string }> {
|
||||
try {
|
||||
console.log('[magicScan] Starting scan process...');
|
||||
if (!supabase) {
|
||||
throw new Error('Supabase client is not initialized. Check environment variables.');
|
||||
}
|
||||
|
||||
// 0. Fetch available tags for constrained generation
|
||||
const systemTags = await getAllSystemTags();
|
||||
const tagNames = systemTags.map(t => t.name);
|
||||
console.log(`[magicScan] Fetched ${tagNames.length} system tags`);
|
||||
|
||||
// 1. AI Analysis
|
||||
let aiResponse: any;
|
||||
|
||||
@@ -18,41 +18,51 @@ export interface Tag {
|
||||
* Fetch tags by category
|
||||
*/
|
||||
export async function getTagsByCategory(category: TagCategory): Promise<Tag[]> {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
try {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('tags')
|
||||
.select('*')
|
||||
.eq('category', category)
|
||||
.order('popularity_score', { ascending: false })
|
||||
.order('name');
|
||||
const { data, error } = await supabase
|
||||
.from('tags')
|
||||
.select('*')
|
||||
.eq('category', category)
|
||||
.order('popularity_score', { ascending: false })
|
||||
.order('name');
|
||||
|
||||
if (error) {
|
||||
console.error(`Error fetching tags for ${category}:`, error);
|
||||
if (error) {
|
||||
console.error(`Error fetching tags for ${category}:`, error);
|
||||
return [];
|
||||
}
|
||||
|
||||
return data || [];
|
||||
} catch (err) {
|
||||
console.error(`Exception in getTagsByCategory for ${category}:`, err);
|
||||
return [];
|
||||
}
|
||||
|
||||
return data || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all system default tags
|
||||
*/
|
||||
export async function getAllSystemTags(): Promise<Tag[]> {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
try {
|
||||
const supabase = createServerActionClient({ cookies });
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('tags')
|
||||
.select('*')
|
||||
.eq('is_system_default', true)
|
||||
.order('name');
|
||||
const { data, error } = await supabase
|
||||
.from('tags')
|
||||
.select('*')
|
||||
.eq('is_system_default', true)
|
||||
.order('name');
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching all system tags:', error);
|
||||
if (error) {
|
||||
console.error('Error fetching all system tags:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
return data || [];
|
||||
} catch (err) {
|
||||
console.error('Exception in getAllSystemTags:', err);
|
||||
return [];
|
||||
}
|
||||
|
||||
return data || [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user