Files
Core_Be/AI/WorkoutPlanOrchestrator.cs
Dhananjaya99 bffc9b1686 first commit
2026-09-28 11:44:26 +05:30

230 lines
12 KiB
C#

using Fitness_core_BE.Helpers;
using System.Text.Json;
namespace Fitness_core_BE.AI
{
public class WorkoutPlanOrchestrator
{
private readonly IAiClient _aiClient;
private readonly ModificationGuard _guard;
public WorkoutPlanOrchestrator(IAiClient aiClient, ModificationGuard guard)
{
_aiClient = aiClient;
_guard = guard;
}
public async Task<object> GeneratePlanAsync(object payload)
{
var data = DeserializePayload.Deserialize(payload);
string fitnessLevel = DataExtractor.GetRequiredString(data, "fitnessLevel");
string goal = DataExtractor.GetRequiredString(data, "goal");
int daysPerWeek = DataExtractor.GetRequiredInt(data, "daysPerWeek");
string availableEquipment = DataExtractor.GetRequiredString(data, "availableEquipment");
int durationMinutes = DataExtractor.GetRequiredInt(data, "durationPerSession");
// Optional fields
string? injuryOrLimitations = data.ContainsKey("injuryOrLimitations")
? data["injuryOrLimitations"].GetString()
: null;
// Basic validation
if (daysPerWeek < 1 || daysPerWeek > 7)
throw new Exception("Days per week must be between 1 and 7");
if (durationMinutes < 15 || durationMinutes > 180)
throw new Exception("Duration must be between 15 and 180 minutes");
//bmi, body shape , target , should check with tartget and body shape matching, time peiod, Continuose-week days,,, whether going to Gym or not, Injuries, any seriose conditions,
var systemPrompt = @"
You are a certified personal trainer and fitness expert.
Your response must be STRICTLY a JSON object.
Output format rules:
1. The first character of your response MUST be {
2. The last character MUST be }
3. Do not include ``` or any markdown formatting
4. Do not include any explanation text
5. Do not include comments
6. Do not prefix with ""Here is""
7. Do not suffix with any text
Return ONLY valid JSON.
Structure:
{
""name"": string,
""description"": string,
""workoutItems"": [
{
""exerciseDay"": string,
""description"": string,
""exercises"": {
""Exercise Name"": ""sets x reps or duration""
},
""duration"": string (total session time including warmup and cooldown, with units),
""wormUp"": string (warmup instructions with an explicit time and unit),
""cooldown"": string (cooldown instructions with an explicit time and unit),
""howToDo"": string (JSON string with rest periods and notes),
""doURL"": string (exercise reference URL)
}
]
}
Important guidelines:
- Create a workout plan based on the user's fitness level, goal, and available equipment
- Include appropriate exercises for the specified number of days per week
- Each workout must fit within the specified duration
- Set ""duration"" to the requested total duration per session (for example, ""45 minutes"")
- ""wormUp"" and ""cooldown"" must each include an explicit duration such as ""5 minutes""
- The main workout time plus wormUp time plus cooldown time must equal the total ""duration""
- The ""exercises"" field should be an object with exercise names as keys and sets/reps as values
- The ""howToDo"" field should be a JSON string containing warmup, rest periods, and notes
- Consider any injury or limitations mentioned
- Provide realistic sets, reps, and rest periods based on fitness level
- Include proper progression and variety
";
var jsonResponse = await _aiClient.GenerateJsonAsync(
systemPrompt,
data
);
// Validate JSON before returning
try
{
var parsed = JsonSerializer.Deserialize<object>(jsonResponse);
if (parsed == null)
throw new Exception("Invalid AI JSON");
}
catch
{
throw new Exception("AI returned invalid JSON structure");
}
return JsonSerializer.Deserialize<object>(jsonResponse)!;
}
public async Task<object> UpdatePlanAsync(object payload)
{
var data = DeserializePayload.Deserialize(payload);
if (!data.ContainsKey("currentWorkoutPlan"))
throw new Exception("Current plan missing");
string modification = DataExtractor.GetRequiredString(data, "modification");
_guard.Validate(modification);
var systemPrompt = @"
You are a professional fitness AI.
You will receive:
1) The current workout plan in valid JSON format.
2) A user modification request in free text.
3) BMI, body shape, target, time period, continuous workout days, whether going to gym or not, injuries, any seriose conditions.
Your task:
- Carefully analyze the modification request.
- Modify ONLY the specific elements explicitly requested by the user.
- Do NOT change anything else.
VERY IMPORTANT RULES:
- Do NOT change the plan name unless the user explicitly asks.
- Do NOT change the number of workout days unless requested.
- Do NOT modify exercises that are not mentioned in the request.
- Do NOT rewrite descriptions unless necessary for the modification.
- Do NOT change sets, reps, or rest periods unless the request requires it.
- Do NOT add or remove exercises unless explicitly requested.
- Do NOT modify workout structure that is unrelated to the request.
- Preserve every unchanged value exactly as provided.
- Analyze the user's BMI, body shape, target, time period, continuous workout days, gym access, injuries, and any seriose conditions.
- Stricly focus if mentioned any seriose health conditions or injuries and do not suggest any exercise that can cause harm to the user.
- If the modification request is not logical or contradicts fitness principles, do not apply it and explain why in the reason field.
Scope control:
If the request only affects one exercise, update only that exercise.
If the request does not affect the plan, return it unchanged.
Preserve the exact internal structure of the workout plan.
Do NOT rename fields.
Do NOT remove required properties.
Do NOT change the JSON schema.
Return your response strictly in this JSON format:
{
""reason"": string,
""modified"": boolean,
""currentPlan"": {
""name"": string,
""description"": string,
""workoutItems"": [
{
""exerciseDay"": string,
""description"": string,
""exercises"": {
""Exercise Name"": ""sets x reps or duration""
},
""howToDo"": string,
""doURL"": string
}
]
},
""updatedPlan"": {
""name"": string,
""description"": string,
""workoutItems"": [
{
""exerciseDay"": string,
""description"": string,
""exercises"": {
""Exercise Name"": ""sets x reps or duration""
},
""howToDo"": string,
""doURL"": string
}
]
}
}
STRICT OUTPUT RULES:
- Return ONLY valid raw JSON.
- No markdown.
- No explanations.
- First character must be {.
- Last character must be }.
- No trailing commas.
- No extra commentary.
If modification cannot be applied:
- Set ""modified"": false
- Keep currentPlan and updatedPlan identical.
- Explain reason clearly.
";
var jsonResponse = await _aiClient.GenerateJsonAsync(
systemPrompt,
data
);
try
{
var parsed = JsonSerializer.Deserialize<object>(jsonResponse);
if (parsed == null)
throw new Exception("Invalid JSON");
}
catch
{
throw new Exception("AI returned invalid JSON");
}
return JsonSerializer.Deserialize<object>(jsonResponse)!;
}
}
}