feat: AI client and prompt templates

This commit is contained in:
2026-05-20 17:47:45 +02:00
parent 278ac112cf
commit 93aad601cf
2 changed files with 97 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
import OpenAI from 'openai';
import { config } from '../config';
export function createAiClient(): OpenAI {
return new OpenAI({
apiKey: config.openrouterApiKey,
baseURL: 'https://openrouter.ai/api/v1',
});
}
+88
View File
@@ -0,0 +1,88 @@
import type { AIContext } from './context';
import { formatDuration } from '../utils/duration';
function sessionLines(ctx: AIContext): string {
if (ctx.recentSessions.length === 0) return 'No sessions recorded yet.';
return ctx.recentSessions
.map(s => ` ${s.date}: ${formatDuration(s.duration_min)}${s.notes ? ` (${s.notes})` : ''}`)
.join('\n');
}
function scheduleLines(ctx: AIContext): string {
if (ctx.upcomingSchedule.length === 0) return 'No upcoming schedule.';
return ctx.upcomingSchedule
.map(e => ` ${e.date}: ${formatDuration(e.planned_min)} [${e.status}]`)
.join('\n');
}
function skipLines(ctx: AIContext): string {
if (ctx.recentSkips.length === 0) return 'None.';
return ctx.recentSkips
.map(s => ` ${s.date}${s.reason ? `: ${s.reason}` : ''}`)
.join('\n');
}
function systemBase(ctx: AIContext): string {
return `You are a supportive personal training coach. You help the user track and improve their anal training practice.
Today: ${ctx.today}
Training goal: ${ctx.goal}
Current streak: ${ctx.currentStreak} sessions
Recent sessions (newest first):
${sessionLines(ctx)}
Upcoming schedule:
${scheduleLines(ctx)}
Recent skips:
${skipLines(ctx)}
Be encouraging but honest. Always explain your reasoning. Flag if you think the pace is too fast or too slow.`;
}
export function progressPrompt(ctx: AIContext): { system: string; user: string } {
return {
system: systemBase(ctx),
user: 'Analyse my recent training history. Give me a summary of my progress, highlight any patterns (positive or negative), and tell me how I\'m tracking toward my goal.',
};
}
export function nextStepPrompt(ctx: AIContext): { system: string; user: string } {
return {
system: systemBase(ctx),
user: 'Based on my history, what should my next training step be? Should I increase duration, maintain, or take a rest? Explain your reasoning.',
};
}
export function reschedulePrompt(ctx: AIContext, note: string | null): { system: string; user: string } {
const extra = note ? `\n\nAdditional context from the user: "${note}"` : '';
return {
system: systemBase(ctx),
user: `Generate a training schedule for the next 14 days starting from ${ctx.today}.${extra}
Respond with ONLY a JSON array — no prose, no markdown explanation — in this exact format:
[
{ "date": "YYYY-MM-DD", "planned_min": 60, "rationale": "reason" }
]
Only include days with planned sessions (rest days are omitted). Space sessions appropriately.`,
};
}
export function setupPrompt(
currentLevel: string, availability: string, goal: string
): { system: string; user: string } {
return {
system: 'You are a supportive personal training coach helping a new user set up their anal training plan. Be warm, practical, and non-judgmental.',
user: `New user setup:
- Current level: ${currentLevel}
- Typical availability: ${availability}
- Goal: ${goal}
Generate a 14-day starter schedule. Respond with ONLY a JSON array in this exact format:
[
{ "date": "YYYY-MM-DD", "planned_min": 30, "rationale": "Starting gently" }
]`,
};
}