Spaces:
Sleeping
Sleeping
Added NLP#2
Browse files- app.py +38 -34
- nlp_service.py +8 -2
app.py
CHANGED
@@ -232,46 +232,19 @@ def extract_expense():
|
|
232 |
extracted_text = "\n".join(extracted_lines)
|
233 |
main_amount_ocr = find_main_amount(ocr_result) # Keep OCR amount extraction
|
234 |
|
235 |
-
# ---
|
236 |
-
nlp_analysis_result = None
|
237 |
-
nlp_error = None
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
print(f"NLP Service Analysis Result: {nlp_analysis_result}")
|
243 |
-
# Check if the NLP analysis itself reported an error/failure
|
244 |
-
if nlp_analysis_result.get("status") == "failed":
|
245 |
-
nlp_error = nlp_analysis_result.get("message", "NLP processing failed")
|
246 |
-
# Keep the result structure but note the failure
|
247 |
-
except Exception as nlp_e:
|
248 |
-
nlp_error = f"Error calling NLP analysis function: {nlp_e}"
|
249 |
-
print(f"Error calling NLP function: {nlp_error}")
|
250 |
-
nlp_analysis_result = None # Ensure result is None on exception during call
|
251 |
-
else:
|
252 |
-
nlp_error = "No text extracted from image for NLP analysis."
|
253 |
-
# --- End NLP Call ---
|
254 |
-
|
255 |
-
# Construct the response
|
256 |
response_data = {
|
257 |
"type": "photo",
|
258 |
"extracted_text": extracted_text,
|
259 |
"main_amount_ocr": main_amount_ocr, # Amount found by OCR regex logic
|
260 |
-
"nlp_analysis": nlp_analysis_result, # Include the full NLP analysis result (or None)
|
261 |
-
"nlp_error": nlp_error # Include any error from NLP call/processing
|
262 |
}
|
263 |
|
264 |
-
# Optional: Add top-level convenience fields based on successful NLP analysis
|
265 |
-
if nlp_analysis_result and nlp_analysis_result.get("status") == "success":
|
266 |
-
if nlp_analysis_result.get("action") == "add_expense":
|
267 |
-
response_data['confirmed_expense_details'] = nlp_analysis_result.get('details')
|
268 |
-
response_data['confirmation_message'] = nlp_analysis_result.get('message')
|
269 |
-
elif nlp_analysis_result.get("action") == "query_expense":
|
270 |
-
# Include query results if applicable (depends on nlp_service structure)
|
271 |
-
response_data['query_message'] = nlp_analysis_result.get('message')
|
272 |
-
response_data['query_criteria'] = nlp_analysis_result.get('criteria')
|
273 |
-
response_data['query_results_count'] = nlp_analysis_result.get('results_count')
|
274 |
-
|
275 |
return jsonify(response_data)
|
276 |
|
277 |
except Exception as e:
|
@@ -285,6 +258,37 @@ def extract_expense():
|
|
285 |
|
286 |
return jsonify({"error": "File processing failed"}), 500
|
287 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
# --- NEW: Health Check Endpoint ---
|
289 |
@app.route('/health', methods=['GET'])
|
290 |
def health_check():
|
|
|
232 |
extracted_text = "\n".join(extracted_lines)
|
233 |
main_amount_ocr = find_main_amount(ocr_result) # Keep OCR amount extraction
|
234 |
|
235 |
+
# --- REMOVED: NLP Call ---
|
236 |
+
# nlp_analysis_result = None
|
237 |
+
# nlp_error = None
|
238 |
+
# ... (removed NLP call logic) ...
|
239 |
+
# --- End Removed NLP Call ---
|
240 |
+
|
241 |
+
# Construct the response (only OCR results)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
response_data = {
|
243 |
"type": "photo",
|
244 |
"extracted_text": extracted_text,
|
245 |
"main_amount_ocr": main_amount_ocr, # Amount found by OCR regex logic
|
|
|
|
|
246 |
}
|
247 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
return jsonify(response_data)
|
249 |
|
250 |
except Exception as e:
|
|
|
258 |
|
259 |
return jsonify({"error": "File processing failed"}), 500
|
260 |
|
261 |
+
# --- NEW: NLP Message Endpoint ---
|
262 |
+
@app.route('/message', methods=['POST'])
|
263 |
+
def process_message():
|
264 |
+
data = request.get_json()
|
265 |
+
if not data or 'text' not in data:
|
266 |
+
return jsonify({"error": "Missing 'text' field in JSON payload"}), 400
|
267 |
+
|
268 |
+
text_message = data['text']
|
269 |
+
if not text_message:
|
270 |
+
return jsonify({"error": "'text' field cannot be empty"}), 400
|
271 |
+
|
272 |
+
nlp_analysis_result = None
|
273 |
+
nlp_error = None
|
274 |
+
try:
|
275 |
+
# Call the imported analysis function
|
276 |
+
nlp_analysis_result = analyze_expense_text(text_message)
|
277 |
+
print(f"NLP Service Analysis Result: {nlp_analysis_result}")
|
278 |
+
# Check if the NLP analysis itself reported an error/failure
|
279 |
+
if nlp_analysis_result.get("status") == "failed":
|
280 |
+
nlp_error = nlp_analysis_result.get("message", "NLP processing failed")
|
281 |
+
# Return the failure result from NLP service
|
282 |
+
return jsonify(nlp_analysis_result), 400 # Or 200 with error status? Let's use 200 for now.
|
283 |
+
|
284 |
+
# Return the successful analysis result
|
285 |
+
return jsonify(nlp_analysis_result)
|
286 |
+
|
287 |
+
except Exception as nlp_e:
|
288 |
+
nlp_error = f"Error calling NLP analysis function: {nlp_e}"
|
289 |
+
print(f"Error calling NLP function: {nlp_error}")
|
290 |
+
return jsonify({"error": "An internal error occurred during NLP processing", "details": nlp_error}), 500
|
291 |
+
|
292 |
# --- NEW: Health Check Endpoint ---
|
293 |
@app.route('/health', methods=['GET'])
|
294 |
def health_check():
|
nlp_service.py
CHANGED
@@ -673,6 +673,7 @@ def call_gemini_api(text, api_key):
|
|
673 |
}
|
674 |
# Construct the payload based on Gemini API requirements
|
675 |
# This prompt asks Gemini to act like the existing NLP service
|
|
|
676 |
prompt = f"""Analyze the following text for expense tracking. Determine the intent ('add_expense' or 'query_expense') and extract relevant details.
|
677 |
|
678 |
Text: "{text}"
|
@@ -721,6 +722,8 @@ Provide only the JSON output.
|
|
721 |
logging.debug(f"Raw Gemini API response: {gemini_response_raw}")
|
722 |
|
723 |
# --- Process gemini_response ---
|
|
|
|
|
724 |
# Extract the text content which should contain the JSON
|
725 |
if 'candidates' in gemini_response_raw and len(gemini_response_raw['candidates']) > 0:
|
726 |
content = gemini_response_raw['candidates'][0].get('content', {}).get('parts', [{}])[0].get('text')
|
@@ -738,10 +741,11 @@ Provide only the JSON output.
|
|
738 |
return parsed_result
|
739 |
else:
|
740 |
logging.warning("Gemini response parsed but lacks expected structure.")
|
|
|
741 |
return {"action": "info", "status": "success", "message": f"Gemini suggestion: {content_cleaned}"}
|
742 |
except json.JSONDecodeError as json_err:
|
743 |
logging.warning(f"Failed to decode JSON from Gemini response: {json_err}. Raw content: {content_cleaned}")
|
744 |
-
# Return the raw text as a message if JSON parsing fails
|
745 |
return {"action": "info", "status": "success", "message": f"Gemini suggestion: {content_cleaned}"}
|
746 |
else:
|
747 |
logging.warning("No text content found in Gemini response candidates.")
|
@@ -763,7 +767,9 @@ Provide only the JSON output.
|
|
763 |
logging.error(f"Gemini API error response (non-JSON): {e.response.text}")
|
764 |
return None
|
765 |
except Exception as e:
|
766 |
-
|
|
|
|
|
767 |
return None
|
768 |
|
769 |
|
|
|
673 |
}
|
674 |
# Construct the payload based on Gemini API requirements
|
675 |
# This prompt asks Gemini to act like the existing NLP service
|
676 |
+
# Corrected indentation for the prompt string
|
677 |
prompt = f"""Analyze the following text for expense tracking. Determine the intent ('add_expense' or 'query_expense') and extract relevant details.
|
678 |
|
679 |
Text: "{text}"
|
|
|
722 |
logging.debug(f"Raw Gemini API response: {gemini_response_raw}")
|
723 |
|
724 |
# --- Process gemini_response ---
|
725 |
+
content = None # Initialize content to None
|
726 |
+
content_cleaned = None # Initialize content_cleaned to None
|
727 |
# Extract the text content which should contain the JSON
|
728 |
if 'candidates' in gemini_response_raw and len(gemini_response_raw['candidates']) > 0:
|
729 |
content = gemini_response_raw['candidates'][0].get('content', {}).get('parts', [{}])[0].get('text')
|
|
|
741 |
return parsed_result
|
742 |
else:
|
743 |
logging.warning("Gemini response parsed but lacks expected structure.")
|
744 |
+
# Return info message if structure is wrong but content exists
|
745 |
return {"action": "info", "status": "success", "message": f"Gemini suggestion: {content_cleaned}"}
|
746 |
except json.JSONDecodeError as json_err:
|
747 |
logging.warning(f"Failed to decode JSON from Gemini response: {json_err}. Raw content: {content_cleaned}")
|
748 |
+
# Return the raw text as a message if JSON parsing fails but content exists
|
749 |
return {"action": "info", "status": "success", "message": f"Gemini suggestion: {content_cleaned}"}
|
750 |
else:
|
751 |
logging.warning("No text content found in Gemini response candidates.")
|
|
|
767 |
logging.error(f"Gemini API error response (non-JSON): {e.response.text}")
|
768 |
return None
|
769 |
except Exception as e:
|
770 |
+
# Include content_cleaned in the log if available during unexpected errors
|
771 |
+
error_context = f"Raw content (if available): {content_cleaned}" if content_cleaned else "No raw content parsed."
|
772 |
+
logging.error(f"An unexpected error occurred during Gemini API call or processing: {e}. {error_context}")
|
773 |
return None
|
774 |
|
775 |
|