From b8f1f124611af81f771621d415b3c7c7102495c0 Mon Sep 17 00:00:00 2001 From: Torben Sorensen Date: Sun, 23 Nov 2025 13:28:46 -0800 Subject: [PATCH] tests cannot connect to db --- src/routes/user.ts | 5 +- src/services/aiService.server.ts | 86 ++++++++++++++++---------------- 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/routes/user.ts b/src/routes/user.ts index 3407e543..f93f4d30 100644 --- a/src/routes/user.ts +++ b/src/routes/user.ts @@ -30,7 +30,10 @@ const upload = multer({ storage: storage }); router.use(passport.authenticate('jwt', { session: false })); // --- User Profile & Account Routes --- -router.use((req, res, next) => { logger.debug(`[UserRouter] HIT ${req.method} ${req.path}`); next(); }); +router.use((req, res, next) => { + console.log(`[UserRouter] HIT: ${req.method} ${req.originalUrl} (Path: ${req.path})`); + next(); +}); router.get('/profile', async (req: Request, res: Response) => { const authenticatedUser = req.user as { id: string; email: string }; diff --git a/src/services/aiService.server.ts b/src/services/aiService.server.ts index 524e32d8..4f46b1dd 100644 --- a/src/services/aiService.server.ts +++ b/src/services/aiService.server.ts @@ -58,31 +58,29 @@ export const extractItemsFromReceiptImage = async ( const imagePart = await serverFileToGenerativePart(imagePath, imageMimeType); - let response; try { - response = await model.generateContent({ + const response = await model.generateContent({ model: 'gemini-2.5-flash', contents: [{ parts: [{text: prompt}, imagePart] }] }); + const text = response.text; + + // Clean up the response to ensure it's valid JSON + const jsonMatch = text?.match(/\[[\s\S]*\]/); + if (!jsonMatch) { + throw new Error('AI response did not contain a valid JSON array.'); + } + + try { + return JSON.parse(jsonMatch[0]); + } catch (e) { + logger.error("Failed to parse JSON from AI response in extractItemsFromReceiptImage", { responseText: text, error: e }); + throw new Error('Failed to parse structured data from the AI response.'); + } } catch (apiError) { logger.error("Google GenAI API call failed in extractItemsFromReceiptImage:", { error: apiError }); throw apiError; // Re-throw to be handled by the caller/global handler } - - const text = response.text; - - // Clean up the response to ensure it's valid JSON - const jsonMatch = text?.match(/\[[\s\S]*\]/); - if (!jsonMatch) { - throw new Error('AI response did not contain a valid JSON array.'); - } - - try { - return JSON.parse(jsonMatch[0]); - } catch (e) { - logger.error("Failed to parse JSON from AI response in extractItemsFromReceiptImage", { responseText: text, error: e }); - throw new Error('Failed to parse structured data from the AI response.'); - } }; /** @@ -131,26 +129,30 @@ export const extractCoreDataFromFlyerImage = async ( ); // 3. Make the API call to Gemini. - const response = await model.generateContent({ + try { + const response = await model.generateContent({ model: 'gemini-2.5-flash', contents: [{ parts: [{ text: prompt }, ...imageParts] }] - }); + }); + const text = response.text; - const text = response.text; + // 4. Clean and parse the AI's response. + const jsonMatch = text?.match(/\{[\s\S]*\}/); + if (!jsonMatch) { + logger.error("AI response for flyer processing did not contain a valid JSON object.", { responseText: text }); + throw new Error('AI response did not contain a valid JSON object.'); + } - // 4. Clean and parse the AI's response. - const jsonMatch = text?.match(/\{[\s\S]*\}/); - if (!jsonMatch) { - logger.error("AI response for flyer processing did not contain a valid JSON object.", { responseText: text }); - throw new Error('AI response did not contain a valid JSON object.'); - } - - try { - return JSON.parse(jsonMatch[0]); - } catch (e) { - logger.error("Failed to parse JSON from AI response in extractCoreDataFromFlyerImage", { responseText: text, error: e }); - throw new Error('Failed to parse structured data from the AI response.'); - } + try { + return JSON.parse(jsonMatch[0]); + } catch (e) { + logger.error("Failed to parse JSON from AI response in extractCoreDataFromFlyerImage", { responseText: text, error: e }); + throw new Error('Failed to parse structured data from the AI response.'); + } + } catch (apiError) { + logger.error("Google GenAI API call failed in extractCoreDataFromFlyerImage:", { error: apiError }); + throw apiError; + } }; /** @@ -165,9 +167,8 @@ export const planTripWithMaps = async (items: FlyerItem[], store: { name: string const topItems = items.slice(0, 5).map(i => i.item).join(', '); const storeName = store?.name || 'the grocery store'; - let response; try { - response = await model.generateContent({ + const response = await model.generateContent({ model: "gemini-2.5-flash", contents: `I have a shopping list with items like ${topItems}. Find the nearest ${storeName} to me and suggest the best route. Also, are there any other specialty stores nearby (like a bakery or butcher) that might have good deals on related items?`, config: { @@ -182,15 +183,16 @@ export const planTripWithMaps = async (items: FlyerItem[], store: { name: string } }, }); - } catch (apiError) { + + // In a real implementation, you would render the map URLs from the sources. + const sources = (response.candidates?.[0]?.groundingMetadata?.groundingChunks || []).map(chunk => ({ + uri: chunk.web?.uri || '', + title: chunk.web?.title || 'Untitled' + })); + return { text: response.text, sources }; + } catch (apiError) { logger.error("Google GenAI API call failed in planTripWithMaps:", { error: apiError }); throw apiError; } - // In a real implementation, you would render the map URLs from the sources. - const sources = (response.candidates?.[0]?.groundingMetadata?.groundingChunks || []).map(chunk => ({ - uri: chunk.web?.uri || '', - title: chunk.web?.title || 'Untitled' - })); - return { text: response.text, sources }; }; \ No newline at end of file