Spaces:
Sleeping
Sleeping
| 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)}" | |
| def hello_bready(): | |
| return "Hello Bready Go!" | |
| 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}) | |
| 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 | |
| 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}) | |
| def uploaded_file(filename): | |
| return send_from_directory(app.config['UPLOAD_FOLDER'], filename) | |
| 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) | |