recipe-rover-api / app /api /routes.py
garvitcpp's picture
Update app/api/routes.py
1b5fcb4 verified
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
@api_bp.route('/form-data', methods=['GET'])
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
@api_bp.route('/recommend', methods=['POST'])
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
@api_bp.route('/extract-recipe-attributes', methods=['POST'])
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
@api_bp.route('/analyze-food-image', methods=['POST'])
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
@api_bp.route('/health', methods=['GET'])
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