89 lines
2.6 KiB
TypeScript
89 lines
2.6 KiB
TypeScript
import { getDatabase } from '@/lib/database';
|
|
import type { FitnessGoal } from '@/lib/database/types';
|
|
|
|
// Import types from database package
|
|
import type {
|
|
FitnessProfile as DBFitnessProfile,
|
|
Recommendation as DBRecommendation,
|
|
} from '@fitai/database';
|
|
|
|
export interface AIContext {
|
|
profile: DBFitnessProfile;
|
|
activeGoals: FitnessGoal[];
|
|
completedGoals: FitnessGoal[];
|
|
recentRecommendations: DBRecommendation[];
|
|
progressSummary: {
|
|
goalsCompleted: number;
|
|
goalsActive: number;
|
|
averageProgress: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Build comprehensive AI context for a user
|
|
* Aggregates fitness profile, goals, and recommendation history
|
|
*/
|
|
export async function buildAIContext(userId: string): Promise<AIContext> {
|
|
const db = await getDatabase();
|
|
|
|
// Fetch fitness profile
|
|
const profile = await db.getFitnessProfileByUserId(userId);
|
|
|
|
if (!profile) {
|
|
throw new Error(`Fitness profile not found for user ${userId}`);
|
|
}
|
|
|
|
// Fetch all fitness goals
|
|
const allGoals = await db.getFitnessGoalsByUserId(userId);
|
|
|
|
// Separate active and completed goals
|
|
const activeGoals = allGoals.filter((g) => g.status === 'active');
|
|
const completedGoals = allGoals.filter((g) => g.status === 'completed');
|
|
|
|
// Get all recommendations
|
|
const allRecommendations = await db.getRecommendationsByUserId(userId);
|
|
|
|
// Filter recent recommendations (last 7 days)
|
|
const sevenDaysAgo = new Date();
|
|
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
|
|
|
const recentRecommendations = allRecommendations
|
|
.filter((r) => new Date(r.createdAt) > sevenDaysAgo)
|
|
.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
|
|
.slice(0, 5);
|
|
|
|
// Calculate progress summary
|
|
const progressSummary = {
|
|
goalsCompleted: completedGoals.length,
|
|
goalsActive: activeGoals.length,
|
|
averageProgress:
|
|
activeGoals.length > 0
|
|
? activeGoals.reduce((sum, g) => sum + (g.progress || 0), 0) / activeGoals.length
|
|
: 0,
|
|
};
|
|
|
|
return {
|
|
profile,
|
|
activeGoals,
|
|
completedGoals,
|
|
recentRecommendations,
|
|
progressSummary,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Format goal for display in AI prompt
|
|
*/
|
|
export function formatGoalForPrompt(goal: FitnessGoal): string {
|
|
const progress = goal.progress || 0;
|
|
const current = goal.currentValue || 0;
|
|
const target = goal.targetValue;
|
|
const unit = goal.unit || '';
|
|
|
|
if (target) {
|
|
return `${goal.title}: ${current}/${target} ${unit} (${progress.toFixed(1)}% complete)`;
|
|
}
|
|
|
|
return `${goal.title}: ${progress.toFixed(1)}% complete`;
|
|
}
|