Update llm_integration.py
Browse files- llm_integration.py +50 -57
llm_integration.py
CHANGED
|
@@ -1,64 +1,57 @@
|
|
| 1 |
-
|
| 2 |
-
from openai import OpenAI
|
| 3 |
import os
|
| 4 |
|
| 5 |
-
client =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
Format the output as a Markdown list, with each day as a bold heading.
|
| 12 |
-
Example:
|
| 13 |
-
**Day 1 - Push**
|
| 14 |
-
- Exercise 1: Sets x Reps
|
| 15 |
-
- Exercise 2: Sets x Reps
|
| 16 |
-
..."""
|
| 17 |
-
|
| 18 |
-
response = client.chat.completions.create(
|
| 19 |
-
model="gemini-2.5-flash",
|
| 20 |
-
messages=[
|
| 21 |
-
{"role": "system", "content": "You are an expert fitness coach providing personalized workout plans."},
|
| 22 |
-
{"role": "user", "content": prompt}
|
| 23 |
-
],
|
| 24 |
-
max_tokens=700,
|
| 25 |
-
temperature=0.7,
|
| 26 |
-
)
|
| 27 |
-
return response.choices[0].message.content
|
| 28 |
-
|
| 29 |
-
def generate_nutrition_with_llm(weight_kg: float, target_kcal: int, liked_csv: str, avoid_csv: str, meals: int) -> str:
|
| 30 |
-
prompt = f"""Generate a personalized daily nutrition plan for someone weighing {weight_kg} kg,
|
| 31 |
-
with a target of {target_kcal} kcal/day, spread across {meals} meals.
|
| 32 |
-
They like these foods: {liked_csv if liked_csv else 'none specified'}.
|
| 33 |
-
They want to avoid these foods: {avoid_csv if avoid_csv else 'none specified'}.
|
| 34 |
-
Provide specific meal ideas for each meal, including approximate macros (protein, carbs, fat) for the day,
|
| 35 |
-
and a general grocery list. Also, include a brief tip for healthy eating.
|
| 36 |
-
Format the output as a Markdown list, with each meal as a bold heading.
|
| 37 |
-
Example:
|
| 38 |
-
### 🥗 Nutrition Plan
|
| 39 |
-
- **Target:** 2000 kcal/day
|
| 40 |
-
- **Macros (approx.):** Protein 150g, Carbs 200g, Fat 60g
|
| 41 |
-
**Meal 1: Breakfast**
|
| 42 |
-
- Scrambled eggs with spinach and whole-wheat toast.
|
| 43 |
-
..."""
|
| 44 |
-
|
| 45 |
-
response = client.chat.completions.create(
|
| 46 |
-
model="gemini-2.5-flash",
|
| 47 |
-
messages=[
|
| 48 |
-
{"role": "system", "content": "You are an expert nutritionist providing personalized meal plans and advice."},
|
| 49 |
-
{"role": "user", "content": prompt}
|
| 50 |
-
],
|
| 51 |
-
max_tokens=800,
|
| 52 |
-
temperature=0.7,
|
| 53 |
-
)
|
| 54 |
-
return response.choices[0].message.content
|
| 55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
-
# LLM-enhanced agent_workout
|
| 58 |
def agent_workout_llm(level: str, days_per_week: int, goal: str, equipment: str) -> str:
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# llm_integration.py
|
|
|
|
| 2 |
import os
|
| 3 |
|
| 4 |
+
# Try to set up an OpenAI client. If anything fails, keep _client=None so the app still runs.
|
| 5 |
+
try:
|
| 6 |
+
from openai import OpenAI
|
| 7 |
+
_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
| 8 |
+
_model = os.getenv("OPENAI_MODEL", "gpt-4o-mini") # change if you use Azure/OpenRouter
|
| 9 |
+
except Exception as e:
|
| 10 |
+
_client = None
|
| 11 |
+
_model = None
|
| 12 |
|
| 13 |
+
DISABLED_MSG = (
|
| 14 |
+
"[LLM disabled] Install 'openai' and set the OPENAI_API_KEY secret "
|
| 15 |
+
"in your Space settings to enable AI-generated plans."
|
| 16 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
+
def _chat(system: str, user: str, temperature: float = 0.4) -> str:
|
| 19 |
+
"""Small helper that calls the model or returns a friendly fallback."""
|
| 20 |
+
if _client is None or _model is None:
|
| 21 |
+
return DISABLED_MSG
|
| 22 |
+
try:
|
| 23 |
+
resp = _client.chat.completions.create(
|
| 24 |
+
model=_model,
|
| 25 |
+
messages=[{"role": "system", "content": system},
|
| 26 |
+
{"role": "user", "content": user}],
|
| 27 |
+
temperature=temperature,
|
| 28 |
+
)
|
| 29 |
+
return (resp.choices[0].message.content or "").strip()
|
| 30 |
+
except Exception as e:
|
| 31 |
+
# Keep the UI responsive even if the API fails
|
| 32 |
+
return f"[LLM error] {e}"
|
| 33 |
|
|
|
|
| 34 |
def agent_workout_llm(level: str, days_per_week: int, goal: str, equipment: str) -> str:
|
| 35 |
+
system = (
|
| 36 |
+
"You are a certified strength coach. Create concise, beginner-safe weekly training plans. "
|
| 37 |
+
"Prefer compound movements, progressive overload, clear sets x reps, and brief cues."
|
| 38 |
+
)
|
| 39 |
+
user = (
|
| 40 |
+
f"Design a {int(days_per_week)}-day plan for a {level} user. "
|
| 41 |
+
f"Goal: {goal}. Equipment: {equipment}. "
|
| 42 |
+
"Format with bullets, include sets x reps, rest times, and 1–2 safety tips."
|
| 43 |
+
)
|
| 44 |
+
return _chat(system, user, temperature=0.35)
|
| 45 |
|
| 46 |
+
def agent_nutrition_llm(weight_kg: float, target_kcal: int,
|
| 47 |
+
liked_csv: str, avoid_csv: str, meals: int) -> str:
|
| 48 |
+
system = (
|
| 49 |
+
"You are a registered dietitian. Provide practical beginner nutrition plans. "
|
| 50 |
+
"Respect preferences and allergies. Keep portions realistic."
|
| 51 |
+
)
|
| 52 |
+
user = (
|
| 53 |
+
f"Create a {int(meals)}-meal/day plan ≈{int(target_kcal)} kcal for a {float(weight_kg)} kg person. "
|
| 54 |
+
f"Preferred foods: {liked_csv or 'none'}. Avoid: {avoid_csv or 'none'}. "
|
| 55 |
+
"Include approximate macros per meal and a short grocery list."
|
| 56 |
+
)
|
| 57 |
+
return _chat(system, user, temperature=0.35)
|