import json from typing import Any from app.llm.client import LLMClient from app.projects.structuring import strip_markdown_json MEAL_PROMPT = """ Преобразуй описание еды в JSON. Только JSON, без markdown. Схема: { "meal_type": "breakfast|lunch|dinner|snack", "description": "краткое описание", "calories": 0, "protein_g": 0, "fat_g": 0, "carbs_g": 0, "estimated": true } Правила: - Оцени ккал и БЖУ по типичным значениям для России/СНГ. - Все числа — float/int, метрическая система (г, ккал). - meal_type угадай из контекста или snack. - estimated всегда true для LLM-оценки. """.strip() WORKOUT_PROMPT = """ Преобразуй описание тренировки в JSON. Только JSON. Формат: { "title": "название", "activity_type": "ходьба|бег|силовая|велосипед|плавание|йога|hiit|другое", "duration_min": null, "active_calories": null, "met": null, "total_calories": null, "steps": null, "notes": "", "exercises": [ {"name": "имя упраж", "sets": 3, "reps": 8, "weight_kg": 80} ] } Правила: - weight_kg в кг, округляй разумно. - active_calories — только если явно указаны в тексте, иначе null. - duration_min — длительность в минутах, если можно оценить из текста. - met — MET по Compendium of Physical Activities, если ккал не указаны (ходьба ~3.5, бег ~9.8, силовая ~6, велосипед ~7.5, плавание ~8, йога ~3, hiit ~8). - activity_type — тип активности для расчёта MET. - total_calories / steps — если упомянуты в тексте, иначе null. - Если данных нет — null или пустой массив. """.strip() STEPS_PROMPT = """ Преобразуй запись о шагах в JSON. Только JSON. Формат: { "steps": 0, "active_calories": null, "notes": "" } Правила: - steps — целое число шагов за день. - active_calories — только если явно указаны. """.strip() async def structure_meal(raw_text: str) -> dict[str, Any]: llm = LLMClient() result = await llm.complete( [ {"role": "system", "content": MEAL_PROMPT}, {"role": "user", "content": raw_text}, ], temperature=0.2, ) raw = strip_markdown_json(result.get("content") or "") return json.loads(raw) async def structure_workout(raw_text: str) -> dict[str, Any]: llm = LLMClient() result = await llm.complete( [ {"role": "system", "content": WORKOUT_PROMPT}, {"role": "user", "content": raw_text}, ], temperature=0.2, ) raw = strip_markdown_json(result.get("content") or "") return json.loads(raw) async def structure_steps(raw_text: str) -> dict[str, Any]: llm = LLMClient() result = await llm.complete( [ {"role": "system", "content": STEPS_PROMPT}, {"role": "user", "content": raw_text}, ], temperature=0.2, ) raw = strip_markdown_json(result.get("content") or "") return json.loads(raw)