from flask import Flask, request, jsonify, redirect, flash, send_from_directory from werkzeug.utils import secure_filename import os import google.generativeai as genai from pymongo import MongoClient import tempfile import PyPDF2 import docx import mammoth from datetime import datetime from PIL import Image import base64 app = Flask(__name__) app.secret_key = 'your_secret_key_here' # Configure Gemini AI genai.configure(api_key="AIzaSyC5-RTbNHj7PX7R-8JOwwUxk6RgWDQtfcA") # Text model text_model = genai.GenerativeModel("gemini-1.5-pro-latest") # Vision model vision_model = genai.GenerativeModel("gemini-1.5-flash") # MongoDB Connection client = MongoClient("mongodb+srv://1mp22cg013:xbnV0QQzx6FMBm2V@cluster0.ilo8duc.mongodb.net/bakery?retryWrites=true&w=majority&appName=Cluster0") db = client.recipe_db # Upload Folder UPLOAD_FOLDER = '/tmp/uploads' # ✅ Use safe writable directory ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'pdf', 'docx'} app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER os.makedirs(UPLOAD_FOLDER, exist_ok=True) # ✅ Won't throw PermissionError in /tmp def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS def ask_baking_bot(user_input): prompt = f""" You are a professional pastry chef and baking expert. Answer only baking, pastry, and cooking-related questions. User's Question: {user_input} """ response = text_model.generate_content(prompt) return response.text def extract_text_from_pdf(pdf_path): try: text = "" with open(pdf_path, 'rb') as file: pdf_reader = PyPDF2.PdfReader(file) for page in pdf_reader.pages: text += page.extract_text() + "\n" return text except Exception as e: return f"Error extracting text from PDF: {str(e)}" def extract_text_from_docx(docx_path): try: with open(docx_path, "rb") as docx_file: result = mammoth.extract_raw_text(docx_file) return result.value except Exception as e: try: doc = docx.Document(docx_path) text = [para.text for para in doc.paragraphs] return '\n'.join(text) except Exception as e2: return f"Error extracting text from DOCX: {str(e)} and {str(e2)}" def parse_recipe_from_text(text): prompt = f""" You are an expert recipe analyzer. Parse the following text from a recipe document and convert it to a structured recipe format. Extract and organize: 1. Recipe title 2. Yield/servings 3. Ingredients list with quantities 4. Step-by-step instructions 5. Baking time and temperature if available 6. Any tips or notes mentioned Format your response in a clean, well-structured way. Recipe text: {text} """ try: response = text_model.generate_content(prompt) return response.text except Exception as e: return f"Error parsing recipe: {str(e)}" def analyze_recipe_steps(recipe_text): prompt = f""" You are a master baker and recipe expert. Analyze the following recipe and provide: 1. Difficulty level (beginner, intermediate, advanced) 2. Common pitfalls or mistakes to avoid 3. Tips for better results 4. Any ingredient substitution suggestions for dietary restrictions 5. Estimated total preparation and cooking time Recipe: {recipe_text} """ try: response = text_model.generate_content(prompt) return response.text except Exception as e: return f"Error analyzing recipe: {str(e)}" def analyze_food_image(image_path): try: image = Image.open(image_path).convert("RGB") prompt = """ You are a professional chef and baking expert. Analyze this food image and provide: 1. What food item this appears to be 2. Key ingredients you can identify 3. Brief assessment of its preparation, texture, and doneness if applicable 4. One tip to improve it if needed Be specific and detailed in your analysis. """ response = vision_model.generate_content([prompt, image]) return response.text except Exception as e: return f"Error analyzing image: {str(e)}" def recognize_ingredients(image_path): try: image = Image.open(image_path).convert("RGB") prompt = """ You are a professional chef and ingredient expert. Please identify all visible ingredients in this image. For each ingredient: 1. Name the ingredient 2. Estimate the approximate quantity if possible 3. Rate the freshness/quality if visible Be as accurate and specific as possible. """ response = vision_model.generate_content([prompt, image]) return response.text except Exception as e: return f"Error recognizing ingredients: {str(e)}" def assess_baking_problem(image_path): try: image = Image.open(image_path).convert("RGB") prompt = """ You are a master baker and troubleshooter. Analyze this baked item and identify: 1. What the item appears to be 2. Any visible issues or problems (texture, color, shape, etc.) 3. The likely causes of these issues 4. Specific remedies and tips to fix these problems next time Be detailed and educational in your response. """ response = vision_model.generate_content([prompt, image]) return response.text except Exception as e: return f"Error assessing baking problem: {str(e)}" @app.route('/') def hello_bready(): return "Hello Bready Go!" @app.route('/ask', methods=['POST']) def ask_question(): user_input = request.form.get('question', '').strip() if not user_input: return jsonify({'error': 'Please enter a question'}), 400 response = ask_baking_bot(user_input) return jsonify({'response': response}) @app.route('/upload', methods=['POST']) def upload_file(): if 'file' not in request.files: return jsonify({'error': 'No file part'}), 400 file = request.files['file'] if file.filename == '': return jsonify({'error': 'No selected file'}), 400 if not file or not allowed_file(file.filename): return jsonify({'error': 'Invalid file type'}), 400 try: filename = secure_filename(file.filename) filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(filepath) action = request.form.get('action', 'analyze') # Get the action from form data if filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif')): if action == 'identify': result = recognize_ingredients(filepath) elif action == 'troubleshoot': result = assess_baking_problem(filepath) else: # Default to general analysis result = analyze_food_image(filepath) return jsonify({ 'analysis': result, 'filename': filename }) elif filename.lower().endswith('.pdf'): text = extract_text_from_pdf(filepath) if action == 'analyze_recipe': parsed_recipe = parse_recipe_from_text(text) analysis = analyze_recipe_steps(parsed_recipe) return jsonify({ 'recipe_analysis': analysis, 'filename': filename }) else: parsed_recipe = parse_recipe_from_text(text) return jsonify({ 'analysis': parsed_recipe, 'filename': filename }) elif filename.lower().endswith(('.docx', '.doc')): text = extract_text_from_docx(filepath) if action == 'analyze_recipe': parsed_recipe = parse_recipe_from_text(text) analysis = analyze_recipe_steps(parsed_recipe) return jsonify({ 'recipe_analysis': analysis, 'filename': filename }) else: parsed_recipe = parse_recipe_from_text(text) return jsonify({ 'analysis': parsed_recipe, 'filename': filename }) except Exception as e: return jsonify({'error': f'Processing failed: {str(e)}'}), 500 @app.route('/analyze_recipe', methods=['POST']) def analyze_recipe(): recipe_text = request.form.get('recipe_text', '').strip() if not recipe_text: return jsonify({'error': 'No recipe text provided'}), 400 analysis = analyze_recipe_steps(recipe_text) return jsonify({'analysis': analysis}) @app.route('/uploads/') def uploaded_file(filename): return send_from_directory(app.config['UPLOAD_FOLDER'], filename) @app.route('/help') def help(): help_info = { 'features': [ { 'title': 'Baking Questions', 'description': 'Ask any baking-related questions and get expert answers from our AI chef.' }, { 'title': 'Recipe Analysis', 'description': 'Upload recipe documents (PDF/DOCX) and get structured recipe information.' }, { 'title': 'Food Image Analysis', 'description': 'Upload images of food to get identification, ingredient analysis, or troubleshooting.' }, { 'title': 'Recipe Scaling', 'description': 'Scale recipes up or down based on serving sizes (coming soon).' }, { 'title': 'Baking Troubleshooting', 'description': 'Get help diagnosing and fixing baking problems from images of your results.' } ] } return jsonify(help_info) # ✅ Modified port to 7860 if __name__ == '__main__': app.run(host='0.0.0.0', port=7860)