Wills17 commited on
Commit
344d8c3
·
verified ·
1 Parent(s): 4ea7b45

Update FastAPI_app.py

Browse files
Files changed (1) hide show
  1. FastAPI_app.py +41 -50
FastAPI_app.py CHANGED
@@ -6,6 +6,7 @@ import io
6
  import time
7
  import traceback
8
  import threading
 
9
 
10
  import uvicorn
11
  import numpy as np
@@ -22,9 +23,6 @@ import tensorflow as tf
22
  import google.generativeai as genai
23
  from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
24
 
25
-
26
-
27
-
28
  # CONFIGURATION
29
 
30
  # Ingredient model (load once)
@@ -47,12 +45,10 @@ else:
47
  'pineapple', 'pomegranate', 'potato', 'raddish', 'soy beans', 'spinach', 'sweetcorn',
48
  'sweetpotato', 'tomato', 'turnip', 'watermelon'
49
  ]
50
-
51
- # Get HF token
52
- hf_token = os.getenv("HF_TOKEN")
53
 
54
- if not hf_token:
55
- raise ValueError("Token not found in environment variable 'HF_TOKEN'.")
 
56
 
57
 
58
  # Thread-safe lazy loading
@@ -60,48 +56,43 @@ _lock = threading.Lock()
60
  _tokenizer = None
61
  _model = None
62
 
63
- def load_gemma2_2b():
64
  global _tokenizer, _model
65
  if _model is not None:
66
  return _tokenizer, _model
67
-
68
  with _lock:
69
  if _model is not None:
70
  return _tokenizer, _model
71
-
72
- print("\n🔵 [Fallback] Loading Gemma-2-2B-it 4-bit")
73
- quantization_config = BitsAndBytesConfig(
74
- load_in_4bit=True,
75
- bnb_4bit_compute_dtype=torch.float16,
76
- bnb_4bit_quant_type="nf4"
77
- )
78
-
79
- _tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-2b-it", token=hf_token)
80
- _model = AutoModelForCausalLM.from_pretrained(
81
- "google/gemma-2-2b-it",
82
- device_map="auto",
83
- quantization_config=quantization_config,
84
- torch_dtype=torch.float16,
85
- trust_remote_code=True
86
- )
87
- print("\n🟢 [Fallback] Gemma-2-2B ready!")
88
- return _tokenizer, _model
89
-
90
- def generate_recipe_gemma(ingredient_names):
91
- tokenizer, model = load_gemma2_2b()
 
 
 
92
 
93
- prompt = f"""<start_of_turn>user
94
- You are an AI chef. Create a short recipe using only: {', '.join(ingredient_names)}.
95
- Include:
96
- - Recipe name
97
- - One-sentence description
98
- - Ingredients list with quantities
99
- - 6-10 concise steps
100
- - Optional tips
101
- RETURN RESULT IN MARKDOWN FORMAT ONLY.<end_of_turn>
102
- <start_of_turn>model
103
- """
104
 
 
 
 
105
  inputs = tokenizer(prompt, return_tensors="pt")
106
  outputs = model.generate(
107
  inputs.input_ids,
@@ -112,7 +103,7 @@ def generate_recipe_gemma(ingredient_names):
112
  )
113
  recipe_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
114
  # Strip the prompt part
115
- return recipe_text.split("<start_of_turn>model")[-1].strip()
116
 
117
 
118
  # Infer uploaded image function
@@ -196,25 +187,25 @@ async def upload_image(file: UploadFile = File(...), user_api_key: str = Form(al
196
  RETURN RESULT IN MARKDOWN FORMAT ONLY.
197
  """
198
 
199
- print("Trying Gemini...")
200
  response = model.generate_content(prompt)
201
  recipe_text = response.text.strip()
202
- print("Gemini succeeded.")
203
 
204
  except Exception as e_gemini:
205
  print("Gemini failed:", e_gemini)
206
  try:
207
- recipe_text = generate_recipe_gemma(ingredient_names)
208
  except Exception as e_local1:
209
- print("Gemma local failed:", e_local1)
210
  raise e_local1
211
 
212
  else:
213
  try:
214
- print("\n🟡 No API key → Using Gemma fallback.")
215
- recipe_text = generate_recipe_gemma(ingredient_names)
216
  except Exception as e_local2:
217
- print("Gemma local failed:", e_local2)
218
  raise e_local2
219
 
220
  return {"ingredients": ingredients, "recipe": recipe_text}
 
6
  import time
7
  import traceback
8
  import threading
9
+ import signal
10
 
11
  import uvicorn
12
  import numpy as np
 
23
  import google.generativeai as genai
24
  from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
25
 
 
 
 
26
  # CONFIGURATION
27
 
28
  # Ingredient model (load once)
 
45
  'pineapple', 'pomegranate', 'potato', 'raddish', 'soy beans', 'spinach', 'sweetcorn',
46
  'sweetpotato', 'tomato', 'turnip', 'watermelon'
47
  ]
 
 
 
48
 
49
+ # Phi-3.5-mini-instruct local model loading
50
+ def timeout_handler(signum, frame):
51
+ raise TimeoutError("Model load timed out after 300s")
52
 
53
 
54
  # Thread-safe lazy loading
 
56
  _tokenizer = None
57
  _model = None
58
 
59
+ def load_phi_3_5_mini_instruct():
60
  global _tokenizer, _model
61
  if _model is not None:
62
  return _tokenizer, _model
63
+
64
  with _lock:
65
  if _model is not None:
66
  return _tokenizer, _model
67
+ signal.signal(signal.SIGALRM, timeout_handler)
68
+ signal.alarm(300) # 5 min timeout
69
+ try:
70
+ print("\n🔵 [Fallback] Loading Phi-3.5-mini-instruct")
71
+ quantization_config = BitsAndBytesConfig(
72
+ load_in_4bit=True,
73
+ bnb_4bit_compute_dtype=torch.float16,
74
+ bnb_4bit_quant_type="nf4"
75
+ )
76
+ _tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3.5-mini-instruct", trust_remote_code=True)
77
+ _model = AutoModelForCausalLM.from_pretrained(
78
+ "microsoft/Phi-3.5-mini-instruct",
79
+ device_map="auto",
80
+ quantization_config=quantization_config,
81
+ torch_dtype=torch.float16,
82
+ trust_remote_code=True
83
+ )
84
+ print("\n🟢 [Fallback] Phi-3.5 ready!")
85
+ return _tokenizer, _model
86
+
87
+ except TimeoutError:
88
+ print("\n🔴 [Fallback] Phi-3.5 load timed out.")
89
+ signal.alarm(0)
90
+ raise RuntimeError("\n🔴 Model load failed.")
91
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
+ def generate_recipe_phi(ingredient_names):
94
+ tokenizer, model = load_phi_3_5_mini_instruct() # Now loads Phi-3
95
+ prompt = f"<|user|>\nYou are an AI chef. Create a short recipe using only: {', '.join(ingredient_names)}.\nInclude:\n- Recipe name\n- One-sentence description\n- Ingredients list with quantities\n- 6-10 concise steps\n- Optional tips\nRETURN RESULT IN MARKDOWN FORMAT ONLY.<|end|>\n<|assistant|>\n"""
96
  inputs = tokenizer(prompt, return_tensors="pt")
97
  outputs = model.generate(
98
  inputs.input_ids,
 
103
  )
104
  recipe_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
105
  # Strip the prompt part
106
+ return recipe_text.split("<|assistant|>")[-1].strip()
107
 
108
 
109
  # Infer uploaded image function
 
187
  RETURN RESULT IN MARKDOWN FORMAT ONLY.
188
  """
189
 
190
+ print("\n🟡 Trying Gemini...")
191
  response = model.generate_content(prompt)
192
  recipe_text = response.text.strip()
193
+ print("\n🟢 Gemini succeeded.")
194
 
195
  except Exception as e_gemini:
196
  print("Gemini failed:", e_gemini)
197
  try:
198
+ recipe_text = generate_recipe_phi(ingredient_names)
199
  except Exception as e_local1:
200
+ print("\n🔴 Phi local failed:", e_local1)
201
  raise e_local1
202
 
203
  else:
204
  try:
205
+ print("\n🟡 No API key → Using Phi-3.5 fallback.")
206
+ recipe_text = generate_recipe_phi(ingredient_names)
207
  except Exception as e_local2:
208
+ print("\n🔴 Phi local failed:", e_local2)
209
  raise e_local2
210
 
211
  return {"ingredients": ingredients, "recipe": recipe_text}