Spaces:
Running
Running
| from flask import Blueprint, Response, request, jsonify, current_app | |
| from app.models.recipe import Recipe | |
| import json | |
| import asyncio | |
| import os | |
| import sys | |
| import traceback | |
| import resource | |
| from app.services import extraction | |
| from app.services import image_query | |
| api_bp = Blueprint('api', __name__, url_prefix='/api') | |
| def log_memory(tag=""): | |
| """Helper to print current RAM usage to logs""" | |
| try: | |
| usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss | |
| # Linux returns KB, convert to MB | |
| usage_mb = usage / 1024 | |
| print(f"[{tag}] MEMORY USAGE: {usage_mb:.2f} MB", file=sys.stderr) | |
| except Exception: | |
| pass | |
| def get_form_data(): | |
| file_path = os.path.join(os.getcwd(), 'form_data.json') | |
| try: | |
| with open(file_path, 'r') as file: | |
| data = file.read() | |
| return data | |
| except FileNotFoundError: | |
| print(f"Error: File not found at {file_path}", file=sys.stderr) | |
| return jsonify({"error": f"File not found at {file_path}"}), 404 | |
| except Exception as e: | |
| traceback.print_exc(file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| async def recommend_recipes(): | |
| print(">>> RECOMMEND ENDPOINT HIT", file=sys.stderr) | |
| log_memory("Start Recommend") | |
| try: | |
| data = request.json | |
| category = data.get('category') | |
| dietary_preference = data.get('dietary_preference') | |
| ingredients = data.get('ingredients', []) | |
| calories = data.get('calories') | |
| time = data.get('time') | |
| keywords = data.get('keywords', []) | |
| keywords_name = data.get('keywords_name', []) | |
| if calories is not None: | |
| calories = int(calories) | |
| if time is not None: | |
| time = int(time) | |
| feature_weights_recommend = { | |
| 'ingredients': 0.15, 'category': 0.25, 'dietary': 0.20, | |
| 'calories': 0.10, 'time': 0.10, 'keywords': 0.10, 'keywords_name': 0.10 | |
| } | |
| recommendations = await current_app.recommendation_system.get_recommendations( | |
| category=category, | |
| dietary_preference=dietary_preference, | |
| ingredients=ingredients, | |
| calories=calories, | |
| time=time, | |
| keywords=keywords, | |
| keywords_name=keywords_name, | |
| feature_weights=feature_weights_recommend | |
| ) | |
| log_memory("End Recommend") | |
| return jsonify([vars(recipe) for recipe in recommendations]) | |
| except Exception as e: | |
| print("!!! CRITICAL ERROR IN RECOMMEND !!!", file=sys.stderr) | |
| traceback.print_exc(file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| async def recommend_recipes2(): | |
| print(">>> SEARCH (EXTRACT) ENDPOINT HIT", file=sys.stderr) | |
| log_memory("Start Search") | |
| try: | |
| data = request.get_json() | |
| if not data: | |
| return jsonify({"error": "No data provided"}), 400 | |
| raw_text = data.get('text') | |
| if not raw_text: | |
| return jsonify({"error": "No search text provided"}), 400 | |
| # 1. Extract Attributes (Using Gemini/AI) | |
| print(f"Extracting attributes for: {raw_text[:50]}...", file=sys.stderr) | |
| extracted_info = extraction.extract_recipe_attributes(raw_text) | |
| if 'error' in extracted_info: | |
| print(f"Extraction Error: {extracted_info}", file=sys.stderr) | |
| return jsonify(extracted_info), 500 | |
| feature_weights_extract = { | |
| 'ingredients': 0.50, 'category': 0.0, 'dietary': 0.0, | |
| 'calories': 0.0, 'time': 0.0, 'keywords': 0.40, 'keywords_name': 0.10 | |
| } | |
| category = extracted_info.get('category', '') | |
| calories = extracted_info.get('calories', None) | |
| time = extracted_info.get('time', None) | |
| keywords = extracted_info.get('keywords', []) | |
| keywords_name = extracted_info.get('keywords_name', []) | |
| ingredients = extracted_info.get('ingredients', []) | |
| try: | |
| calories = int(calories) if calories else None | |
| time = int(time) if time else None | |
| except (ValueError, TypeError): | |
| return jsonify({"error": "Invalid calories or time value"}), 400 | |
| # 2. Get Recommendations (Using Huge DataFrame) | |
| print("Calling Recommendation System...", file=sys.stderr) | |
| recommendations = await current_app.recommendation_system.get_recommendations( | |
| category=category, | |
| ingredients=ingredients, | |
| calories=calories, | |
| time=time, | |
| keywords=keywords, | |
| keywords_name=keywords_name, | |
| feature_weights=feature_weights_extract | |
| ) | |
| log_memory("End Search") | |
| recipe_list = [vars(recipe) for recipe in recommendations] | |
| return jsonify(recipe_list) | |
| except Exception as e: | |
| print("!!! CRITICAL ERROR IN SEARCH !!!", file=sys.stderr) | |
| # This is the line that will finally show you WHY it crashes | |
| traceback.print_exc(file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| async def handle_analyze_food_image(): | |
| print(">>> IMAGE ANALYSIS ENDPOINT HIT", file=sys.stderr) | |
| log_memory("Start Image") | |
| try: | |
| if 'image' not in request.files: | |
| return jsonify({"error": "No image file provided"}), 400 | |
| file = request. files['image'] | |
| if file.filename == '': | |
| return jsonify({"error": "No selected file"}), 400 | |
| print("Analyzing Food Image...", file=sys.stderr) | |
| description = image_query.analyze_food_image(file) | |
| print(f"Image Description: {description[:50]}...", file=sys.stderr) | |
| # 🔥 ADD MORE LOGGING HERE | |
| print(f"Full Image Description: {description}", file=sys.stderr) | |
| extracted_info = extraction.extract_recipe_attributes(description) | |
| # 🔥 LOG THE EXTRACTION RESULT | |
| print(f"Extraction Result: {extracted_info}", file=sys.stderr) | |
| if 'error' in extracted_info: | |
| # 🔥 DON'T STOP - CONTINUE WITH EMPTY VALUES | |
| print(f"Extraction warning (continuing anyway): {extracted_info}", file=sys.stderr) | |
| extracted_info = { | |
| "category": "", | |
| "calories": None, | |
| "time": None, | |
| "keywords": description.split(', ')[: 5], # Use first 5 words from description | |
| "keywords_name": description.split(', ')[:3], | |
| "ingredients": description.split(', ') | |
| } | |
| feature_weights_extract = { | |
| 'ingredients': 0.50, | |
| 'category': 0.0, | |
| 'dietary': 0.0, | |
| 'calories': 0.0, | |
| 'time': 0.0, | |
| 'keywords': 0.40, | |
| 'keywords_name': 0.10 | |
| } | |
| category = extracted_info.get('category', '') | |
| calories = extracted_info.get('calories', None) | |
| time = extracted_info. get('time', None) | |
| keywords = extracted_info.get('keywords', []) | |
| keywords_name = extracted_info.get('keywords_name', []) | |
| ingredients = extracted_info.get('ingredients', []) | |
| try: | |
| calories = int(calories) if calories else None | |
| time = int(time) if time else None | |
| except (ValueError, TypeError): | |
| calories = None | |
| time = None | |
| print("Calling Recommendation System...", file=sys.stderr) | |
| recommendations = await current_app.recommendation_system.get_recommendations( | |
| category=category, | |
| ingredients=ingredients, | |
| calories=calories, | |
| time=time, | |
| keywords=keywords, | |
| keywords_name=keywords_name, | |
| feature_weights=feature_weights_extract | |
| ) | |
| log_memory("End Image") | |
| recipe_list = [vars(recipe) for recipe in recommendations] | |
| return jsonify(recipe_list) | |
| except Exception as e: | |
| print("! !! CRITICAL ERROR IN IMAGE ANALYSIS !! !", file=sys.stderr) | |
| traceback.print_exc(file=sys.stderr) | |
| return jsonify({"error": str(e)}), 500 | |
| def health_check(): | |
| return jsonify({ | |
| "status": "alive", | |
| "message": "Recipe Recommendation Service is Running", | |
| "endpoints": [ | |
| "/api/form-data", | |
| "/api/recommend", | |
| "/api/extract-recipe-attributes", | |
| "/api/analyze-food-image" | |
| ] | |
| }), 200 |