1- const Receipt = require ( '../models/Receipt' ) ;
2- const IncomeExpense = require ( '../models/IncomeExpense' ) ;
3- const { GoogleGenerativeAI } = require ( "@google/generative-ai" ) ;
4- const fs = require ( 'fs' ) ;
1+ const Receipt = require ( "../models/Receipt" ) ;
2+ const IncomeExpense = require ( "../models/IncomeExpense" ) ;
3+ const { GoogleGenAI } = require ( "@google/genai" ) ;
54
6- const genAI = new GoogleGenerativeAI ( process . env . GEMINI_API_KEY ) ;
5+ const fs = require ( "fs" ) ;
6+
7+ const client = new GoogleGenAI ( {
8+ apiKey : process . env . GEMINI_API_KEY ,
9+ } ) ;
710
811// Helper function to convert a file to a format Gemini can understand
912function fileToGenerativePart ( path , mimeType ) {
1013 return {
1114 inlineData : {
1215 data : fs . readFileSync ( path ) . toString ( "base64" ) ,
13- mimeType
16+ mimeType,
1417 } ,
1518 } ;
1619}
@@ -20,12 +23,10 @@ function fileToGenerativePart(path, mimeType) {
2023// @access Private
2124const uploadReceipt = async ( req , res ) => {
2225 if ( ! req . file ) {
23- return res . status ( 400 ) . json ( { message : ' Please upload a file' } ) ;
26+ return res . status ( 400 ) . json ( { message : " Please upload a file" } ) ;
2427 }
2528
2629 try {
27- const model = genAI . getGenerativeModel ( { model : "gemini-1.5-flash-latest" } ) ;
28-
2930 const prompt = `
3031 Analyze this receipt image. Extract the following details:
3132 - merchant: The name of the store or merchant.
@@ -36,24 +37,39 @@ const uploadReceipt = async (req, res) => {
3637 Return the result as a single, minified JSON object. For example:
3738 {"merchant":"Walmart","amount":42.97,"date":"2025-09-13","category":"Groceries"}
3839 ` ;
39-
40+
4041 const imagePart = fileToGenerativePart ( req . file . path , req . file . mimetype ) ;
4142
42- const result = await model . generateContent ( [ prompt , imagePart ] ) ;
43- const response = await result . response ;
44- let text = response . text ( ) ;
43+ const result = await client . models . generateContent ( {
44+ model : "gemini-2.5-flash-lite" ,
45+ contents : [ { role : "user" , parts : [ { text : prompt } , imagePart ] } ] ,
46+ } ) ;
47+
48+ const raw =
49+ result . candidates ?. [ 0 ] ?. content ?. parts ?. map ( ( p ) => p . text ) . join ( "\n\n" ) ??
50+ "" ;
4551
46- text = text . replace ( / ` ` ` j s o n / g, '' ) . replace ( / ` ` ` / g, '' ) . trim ( ) ;
47- const extractedData = JSON . parse ( text ) ;
52+ const cleanedText = raw
53+ . replace ( / ^ [ \s ` ] * ` ` ` j s o n [ \s ` ] * / i, "" ) // Remove opening ```json with spaces
54+ . replace ( / [ \s ` ] * ` ` ` $ / i, "" ) // Remove closing ```
55+ . trim ( ) ;
56+
57+ let extractedData ;
58+ try {
59+ extractedData = JSON . parse ( cleanedText ) ;
60+ } catch ( e ) {
61+ console . warn ( "[Gemini] Invalid JSON, fallback to defaults." , e ) ;
62+ extractedData = { } ;
63+ }
4864
4965 const newReceipt = new Receipt ( {
5066 user : req . user . id ,
5167 fileUrl : `/uploads/${ req . file . filename } ` ,
5268 extractedData : {
5369 amount : extractedData . amount || 0 ,
54- category : extractedData . category || ' Miscellaneous' ,
70+ category : extractedData . category || " Miscellaneous" ,
5571 date : extractedData . date ? new Date ( extractedData . date ) : new Date ( ) ,
56- merchant : extractedData . merchant || ' Unknown Merchant' ,
72+ merchant : extractedData . merchant || " Unknown Merchant" ,
5773 } ,
5874 } ) ;
5975
@@ -73,10 +89,14 @@ const uploadReceipt = async (req, res) => {
7389 }
7490
7591 res . status ( 201 ) . json ( savedReceipt ) ;
76-
7792 } catch ( error ) {
78- console . error ( 'Error with Gemini API:' , error ) ;
79- res . status ( 500 ) . json ( { message : 'Failed to process receipt with AI' , error : error . message } ) ;
93+ console . error ( "Error with Gemini API:" , error ) ;
94+ res
95+ . status ( 500 )
96+ . json ( {
97+ message : "Failed to process receipt with AI" ,
98+ error : error . message ,
99+ } ) ;
80100 } finally {
81101 // Deleting the temporary file from the server
82102 fs . unlinkSync ( req . file . path ) ;
@@ -85,4 +105,4 @@ const uploadReceipt = async (req, res) => {
85105
86106module . exports = {
87107 uploadReceipt,
88- } ;
108+ } ;
0 commit comments