TimInf commited on
Commit
a1a1a43
·
verified ·
1 Parent(s): b80a6fd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +150 -21
app.py CHANGED
@@ -13,12 +13,12 @@ bert_tokenizer = AutoTokenizer.from_pretrained(bert_model_name)
13
  bert_model = AutoModel.from_pretrained(bert_model_name)
14
  bert_model.eval() # Setze das Modell in den Evaluationsmodus
15
 
16
- # Lade T5 Rezeptgenerierungsmodell (NEU hinzugefügt)
17
  MODEL_NAME_OR_PATH = "flax-community/t5-recipe-generation"
18
  t5_tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME_OR_PATH, use_fast=True)
19
  t5_model = FlaxAutoModelForSeq2SeqLM.from_pretrained(MODEL_NAME_OR_PATH) # Modell wird jetzt auch geladen
20
 
21
- # Token Mapping für die T5 Modell-Ausgabe (bleibt hier, obwohl T5 noch nicht aktiv generiert)
22
  special_tokens = t5_tokenizer.all_special_tokens
23
  tokens_map = {
24
  "<sep>": "--",
@@ -92,36 +92,163 @@ def find_best_ingredients(required_ingredients, available_ingredients, max_ingre
92
  return final_ingredients[:max_ingredients]
93
 
94
 
95
- # mock_generate_recipe (ANGEPASST, um zu bestätigen, dass BEIDE Modelle geladen sind)
96
- def mock_generate_recipe(ingredients_list):
97
- """Generiert ein Mock-Rezept und bestätigt das Laden beider Modelle."""
98
- title = f"Rezepttest mit {', '.join(ingredients_list[:3])}" if ingredients_list else "Testrezept"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  return {
100
- "title": title,
101
- "ingredients": ingredients_list,
102
- "directions": [
103
- "Dies ist ein Testrezept.",
104
- "RecipeBERT und T5-Modell wurden beide erfolgreich geladen!",
105
- "Die Zutaten wurden mit RecipeBERT-Intelligenz ausgewählt.",
106
- f"Basierend auf deinen Eingaben wurde '{ingredients_list[-1]}' als ähnlichste Zutat hinzugefügt." if len(ingredients_list) > 1 else "Keine zusätzliche Zutat hinzugefügt."
107
- ],
108
- "used_ingredients": ingredients_list
109
  }
110
 
111
 
 
112
  def process_recipe_request_logic(required_ingredients, available_ingredients, max_ingredients, max_retries):
113
  """
114
  Kernlogik zur Verarbeitung einer Rezeptgenerierungsanfrage.
 
115
  """
116
  if not required_ingredients and not available_ingredients:
117
  return {"error": "Keine Zutaten angegeben"}
 
118
  try:
 
119
  optimized_ingredients = find_best_ingredients(
120
- required_ingredients, available_ingredients, max_ingredients
 
 
121
  )
122
-
123
- recipe = mock_generate_recipe(optimized_ingredients) # Rufe die Mock-Generierungsfunktion auf
124
-
 
 
125
  result = {
126
  'title': recipe['title'],
127
  'ingredients': recipe['ingredients'],
@@ -129,11 +256,13 @@ def process_recipe_request_logic(required_ingredients, available_ingredients, ma
129
  'used_ingredients': optimized_ingredients
130
  }
131
  return result
 
132
  except Exception as e:
133
  return {"error": f"Fehler bei der Rezeptgenerierung: {str(e)}"}
134
 
 
135
  # --- FastAPI-Implementierung ---
136
- app = FastAPI(title="AI Recipe Generator API (Both Models Loaded Test)")
137
 
138
  class RecipeRequest(BaseModel):
139
  required_ingredients: list[str] = []
@@ -158,6 +287,6 @@ async def generate_recipe_api(request_data: RecipeRequest):
158
 
159
  @app.get("/")
160
  async def read_root():
161
- return {"message": "AI Recipe Generator API is running (Both models loaded for test)!"} # Angepasste Nachricht
162
 
163
  print("INFO: FastAPI application script finished execution and defined 'app' variable.")
 
13
  bert_model = AutoModel.from_pretrained(bert_model_name)
14
  bert_model.eval() # Setze das Modell in den Evaluationsmodus
15
 
16
+ # Lade T5 Rezeptgenerierungsmodell
17
  MODEL_NAME_OR_PATH = "flax-community/t5-recipe-generation"
18
  t5_tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME_OR_PATH, use_fast=True)
19
  t5_model = FlaxAutoModelForSeq2SeqLM.from_pretrained(MODEL_NAME_OR_PATH) # Modell wird jetzt auch geladen
20
 
21
+ # Token Mapping für die T5 Modell-Ausgabe
22
  special_tokens = t5_tokenizer.all_special_tokens
23
  tokens_map = {
24
  "<sep>": "--",
 
92
  return final_ingredients[:max_ingredients]
93
 
94
 
95
+ # skip_special_tokens (unverändert, wird von generate_recipe_with_t5 genutzt)
96
+ def skip_special_tokens(text, special_tokens):
97
+ """Entfernt spezielle Tokens aus dem Text"""
98
+ for token in special_tokens:
99
+ text = text.replace(token, "")
100
+ return text
101
+
102
+ # target_postprocessing (unverändert, wird von generate_recipe_with_t5 genutzt)
103
+ def target_postprocessing(texts, special_tokens):
104
+ """Post-processed generierten Text"""
105
+ if not isinstance(texts, list):
106
+ texts = [texts]
107
+
108
+ new_texts = []
109
+ for text in texts:
110
+ text = skip_special_tokens(text, special_tokens)
111
+
112
+ for k, v in tokens_map.items():
113
+ text = text.replace(k, v)
114
+
115
+ new_texts.append(text)
116
+
117
+ return new_texts
118
+
119
+ # validate_recipe_ingredients (unverändert, wird von generate_recipe_with_t5 genutzt)
120
+ def validate_recipe_ingredients(recipe_ingredients, expected_ingredients, tolerance=0):
121
+ """
122
+ Validiert, ob das Rezept ungefähr die erwarteten Zutaten enthält.
123
+ """
124
+ recipe_count = len([ing for ing in recipe_ingredients if ing and ing.strip()])
125
+ expected_count = len(expected_ingredients)
126
+ return abs(recipe_count - expected_count) == tolerance
127
+
128
+
129
+ # generate_recipe_with_t5 (jetzt AKTIVIERT)
130
+ def generate_recipe_with_t5(ingredients_list, max_retries=5):
131
+ """Generiert ein Rezept mit dem T5 Rezeptgenerierungsmodell mit Validierung."""
132
+ original_ingredients = ingredients_list.copy()
133
+
134
+ for attempt in range(max_retries):
135
+ try:
136
+ # Für Wiederholungsversuche nach dem ersten Versuch, mische die Zutaten
137
+ if attempt > 0:
138
+ current_ingredients = original_ingredients.copy()
139
+ random.shuffle(current_ingredients)
140
+ else:
141
+ current_ingredients = ingredients_list
142
+
143
+ # Formatiere Zutaten als kommaseparierten String
144
+ ingredients_string = ", ".join(current_ingredients)
145
+ prefix = "items: "
146
+
147
+ # Generationseinstellungen
148
+ generation_kwargs = {
149
+ "max_length": 512,
150
+ "min_length": 64,
151
+ "do_sample": True,
152
+ "top_k": 60,
153
+ "top_p": 0.95
154
+ }
155
+ # print(f"Versuch {attempt + 1}: {prefix + ingredients_string}")
156
+
157
+ # Tokenisiere Eingabe
158
+ inputs = t5_tokenizer(
159
+ prefix + ingredients_string,
160
+ max_length=256,
161
+ padding="max_length",
162
+ truncation=True,
163
+ return_tensors="jax"
164
+ )
165
+
166
+ # Generiere Text
167
+ output_ids = t5_model.generate(
168
+ input_ids=inputs.input_ids,
169
+ attention_mask=inputs.attention_mask,
170
+ **generation_kwargs
171
+ )
172
+
173
+ # Dekodieren und Nachbearbeiten
174
+ generated = output_ids.sequences
175
+ generated_text = target_postprocessing(
176
+ t5_tokenizer.batch_decode(generated, skip_special_tokens=False),
177
+ special_tokens
178
+ )[0]
179
+
180
+ # Abschnitte parsen
181
+ recipe = {}
182
+ sections = generated_text.split("\n")
183
+ for section in sections:
184
+ section = section.strip()
185
+ if section.startswith("title:"):
186
+ recipe["title"] = section.replace("title:", "").strip().capitalize()
187
+ elif section.startswith("ingredients:"):
188
+ ingredients_text = section.replace("ingredients:", "").strip()
189
+ recipe["ingredients"] = [item.strip().capitalize() for item in ingredients_text.split("--") if item.strip()]
190
+ elif section.startswith("directions:"):
191
+ directions_text = section.replace("directions:", "").strip()
192
+ recipe["directions"] = [step.strip().capitalize() for step in directions_text.split("--") if step.strip()]
193
+
194
+ # Wenn der Titel fehlt, erstelle einen
195
+ if "title" not in recipe:
196
+ recipe["title"] = f"Rezept mit {', '.join(current_ingredients[:3])}"
197
+
198
+ # Stelle sicher, dass alle Abschnitte existieren
199
+ if "ingredients" not in recipe:
200
+ recipe["ingredients"] = current_ingredients
201
+ if "directions" not in recipe:
202
+ recipe["directions"] = ["Keine Anweisungen generiert"]
203
+
204
+ # Validiere das Rezept
205
+ if validate_recipe_ingredients(recipe["ingredients"], original_ingredients):
206
+ # print(f"Erfolg bei Versuch {attempt + 1}: Rezept hat die richtige Anzahl von Zutaten")
207
+ return recipe
208
+ else:
209
+ # print(f"Versuch {attempt + 1} fehlgeschlagen: Erwartet {len(original_ingredients)} Zutaten, erhalten {len(recipe['ingredients'])}")
210
+ if attempt == max_retries - 1:
211
+ # print("Maximale Wiederholungsversuche erreicht, letztes generiertes Rezept wird zurückgegeben")
212
+ return recipe
213
+
214
+ except Exception as e:
215
+ # print(f"Fehler bei der Rezeptgenerierung Versuch {attempt + 1}: {str(e)}")
216
+ if attempt == max_retries - 1:
217
+ return {
218
+ "title": f"Rezept mit {original_ingredients[0] if original_ingredients else 'Zutaten'}",
219
+ "ingredients": original_ingredients,
220
+ "directions": ["Fehler beim Generieren der Rezeptanweisungen"]
221
+ }
222
+
223
+ # Fallback (sollte nicht erreicht werden)
224
  return {
225
+ "title": f"Rezept mit {original_ingredients[0] if original_ingredients else 'Zutaten'}",
226
+ "ingredients": original_ingredients,
227
+ "directions": ["Fehler beim Generieren der Rezeptanweisungen"]
 
 
 
 
 
 
228
  }
229
 
230
 
231
+ # process_recipe_request_logic (JETZT RUFT generate_recipe_with_t5 auf)
232
  def process_recipe_request_logic(required_ingredients, available_ingredients, max_ingredients, max_retries):
233
  """
234
  Kernlogik zur Verarbeitung einer Rezeptgenerierungsanfrage.
235
+ Ausgelagert, um von verschiedenen Endpunkten aufgerufen zu werden.
236
  """
237
  if not required_ingredients and not available_ingredients:
238
  return {"error": "Keine Zutaten angegeben"}
239
+
240
  try:
241
+ # Optimale Zutaten finden (mit RecipeBERT)
242
  optimized_ingredients = find_best_ingredients(
243
+ required_ingredients,
244
+ available_ingredients,
245
+ max_ingredients
246
  )
247
+
248
+ # Rezept mit optimierten Zutaten generieren (JETZT MIT T5!)
249
+ recipe = generate_recipe_with_t5(optimized_ingredients, max_retries)
250
+
251
+ # Ergebnis formatieren
252
  result = {
253
  'title': recipe['title'],
254
  'ingredients': recipe['ingredients'],
 
256
  'used_ingredients': optimized_ingredients
257
  }
258
  return result
259
+
260
  except Exception as e:
261
  return {"error": f"Fehler bei der Rezeptgenerierung: {str(e)}"}
262
 
263
+
264
  # --- FastAPI-Implementierung ---
265
+ app = FastAPI(title="AI Recipe Generator API (Full Functionality)")
266
 
267
  class RecipeRequest(BaseModel):
268
  required_ingredients: list[str] = []
 
287
 
288
  @app.get("/")
289
  async def read_root():
290
+ return {"message": "AI Recipe Generator API is running (Full functionality activated)!"} # Angepasste Nachricht
291
 
292
  print("INFO: FastAPI application script finished execution and defined 'app' variable.")