roshcheeku commited on
Commit
75ff899
Β·
verified Β·
1 Parent(s): 391649b

Upload 4 files

Browse files
app.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ from flask_cors import CORS
3
+ from werkzeug.utils import secure_filename
4
+ import os
5
+ import pandas as pd
6
+ import numpy as np
7
+ import joblib
8
+ import re
9
+ import string
10
+ from PIL import Image
11
+ from pymongo import MongoClient
12
+ from sklearn.feature_extraction.text import TfidfVectorizer
13
+ from sklearn.linear_model import LogisticRegression
14
+ from sklearn.metrics.pairwise import cosine_similarity
15
+ import google.generativeai as genai
16
+ import speech_recognition as sr
17
+ import pyttsx3
18
+
19
+ app = Flask(__name__)
20
+ CORS(app) # Enable CORS for all routes
21
+
22
+ # === Configuration ===
23
+ UPLOAD_FOLDER = 'uploads'
24
+ ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'pdf', 'docx', 'wav', 'mp3'}
25
+ app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
26
+ app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB
27
+
28
+ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
29
+
30
+ # === Gemini API Config ===
31
+ genai.configure(api_key="AIzaSyC5-RTbNHj7PX7R-8JOwwUxk6RgWDQtfcA")
32
+ text_model = genai.GenerativeModel("gemini-1.5-pro-latest")
33
+ vision_model = genai.GenerativeModel("gemini-1.5-flash")
34
+
35
+ # === Voice Tools ===
36
+ recognizer = sr.Recognizer()
37
+ engine = pyttsx3.init()
38
+
39
+ # === Load Dataset ===
40
+ df = pd.read_csv(r"C:\Users\dhanyashree\OneDrive\Desktop\final_substitution.csv")
41
+ df.columns = df.columns.str.lower()
42
+ df.rename(columns={'food label': 'ingredient', 'substitution label': 'substitute'}, inplace=True)
43
+ if 'ingredient' not in df.columns or 'substitute' not in df.columns:
44
+ raise ValueError("CSV must contain 'ingredient' and 'substitute' columns.")
45
+
46
+ # === Preprocessing & Model Training ===
47
+ def preprocess_text(text):
48
+ if isinstance(text, str):
49
+ text = text.lower()
50
+ text = re.sub(r'\d+', '', text)
51
+ text = text.translate(str.maketrans('', '', string.punctuation))
52
+ text = text.strip()
53
+ return text
54
+
55
+ df['ingredient_clean'] = df['ingredient'].apply(preprocess_text)
56
+ df['substitute_clean'] = df['substitute'].apply(preprocess_text)
57
+
58
+ vectorizer = TfidfVectorizer()
59
+ X = vectorizer.fit_transform(df['ingredient_clean'])
60
+ y = df['substitute_clean']
61
+
62
+ model_ml = LogisticRegression()
63
+ model_ml.fit(X, y)
64
+
65
+ # Save models
66
+ joblib.dump(model_ml, "ingredient_substitution_model.pkl")
67
+ joblib.dump(vectorizer, "tfidf_vectorizer.pkl")
68
+
69
+ # === MongoDB for Recipe Scaling ===
70
+ client = MongoClient("mongodb://localhost:27017/")
71
+ db = client.recipe_db
72
+
73
+ # === In-memory conversation history ===
74
+ conversation_history = []
75
+
76
+ # === Allowed File Types ===
77
+ def allowed_file(filename):
78
+ return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
79
+
80
+ # === Helper: Ask Gemini Bot ===
81
+ def ask_baking_bot(user_input):
82
+ prompt = f"""
83
+ You are a professional pastry chef and baking expert.
84
+ Only answer questions about baking, pastry, and cooking.
85
+ User's Question: {user_input}
86
+ """
87
+ response = text_model.generate_content(prompt)
88
+ return response.text
89
+
90
+ # === Helper: Suggest Substitute ===
91
+ def suggest_substitute(query):
92
+ query = preprocess_text(query)
93
+ query_vec = vectorizer.transform([query])
94
+ try:
95
+ predicted_substitute = model_ml.predict(query_vec)[0]
96
+ ai_verification = ask_baking_bot(f"Is {predicted_substitute} a valid substitute for {query}?")
97
+ if query.lower() in ai_verification.lower():
98
+ return f"βœ… ML & Gemini Verified Substitute: {predicted_substitute}"
99
+ except:
100
+ pass
101
+ similarity_scores = cosine_similarity(query_vec, X)
102
+ best_match_idx = np.argmax(similarity_scores)
103
+ return f"πŸ” Suggested Substitute (Similarity-Based): {df.iloc[best_match_idx]['substitute_clean']}"
104
+
105
+ # === Endpoint: Ask Question ===
106
+ @app.route('/api/ask', methods=['POST'])
107
+ def ask_question():
108
+ data = request.get_json()
109
+ if not data or 'question' not in data:
110
+ error_response = {"error": "Missing 'question' in request"}
111
+ print("❌ Error:", error_response)
112
+ return jsonify(error_response), 400
113
+
114
+ question = data['question']
115
+ response = ask_baking_bot(question)
116
+
117
+ conversation_history.append({"user": question, "assistant": response})
118
+ response_data = {"question": question, "response": response}
119
+
120
+ print("βœ… Response to frontend:", response_data)
121
+ return jsonify(response_data)
122
+
123
+ # === Endpoint: Analyze Image ===
124
+ @app.route('/api/analyze-image', methods=['POST'])
125
+ def analyze_image_endpoint():
126
+ if 'file' not in request.files:
127
+ error_response = {"error": "No file uploaded"}
128
+ print("❌ Error:", error_response)
129
+ return jsonify(error_response), 400
130
+
131
+ file = request.files['file']
132
+ if file.filename == '':
133
+ error_response = {"error": "No selected file"}
134
+ print("❌ Error:", error_response)
135
+ return jsonify(error_response), 400
136
+
137
+ if file and allowed_file(file.filename):
138
+ filename = secure_filename(file.filename)
139
+ filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
140
+ file.save(filepath)
141
+
142
+ try:
143
+ analysis = analyze_food_image(filepath)
144
+ os.unlink(filepath)
145
+ response_data = {"image": filename, "analysis": analysis}
146
+ print("πŸ“· Image Analysis Response:", response_data)
147
+ return jsonify(response_data)
148
+ except Exception as e:
149
+ error_response = {"error": str(e)}
150
+ print("❌ Error:", error_response)
151
+ return jsonify(error_response), 500
152
+
153
+ error_response = {"error": "Invalid file type"}
154
+ print("❌ Error:", error_response)
155
+ return jsonify(error_response), 400
156
+
157
+ # === Helper: Analyze Image with Gemini ===
158
+ def analyze_food_image(image_path):
159
+ try:
160
+ image = Image.open(image_path)
161
+ if image.mode != "RGB":
162
+ image = image.convert("RGB")
163
+ prompt = """
164
+ You are a professional chef and baking expert.
165
+ Analyze this food image and provide:
166
+ 1. Likely food item
167
+ 2. Key ingredients visible
168
+ 3. Comments on preparation and doneness
169
+ 4. Tip for improvement if needed
170
+ """
171
+ response = vision_model.generate_content([prompt, image])
172
+ return response.text
173
+ except Exception as e:
174
+ return f"Error analyzing image: {str(e)}"
175
+
176
+ # === Run App ===
177
+ if __name__ == '__main__':
178
+ app.run(debug=True)
final_substitution.csv ADDED
The diff for this file is too large to render. See raw diff
 
ingredient_substitution_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b2a256abf44dfa50892d27ce6d30810993d812229ed0061b157236b3667ebd0e
3
+ size 2848919
tfidf_vectorizer.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5ae3af8094996956e893987f747481e5c6b3b595c3db00259ea67397943b6f11
3
+ size 15021