feat: AI-generated skincare routine suggestions (single + batch)

Add Gemini-powered endpoints and frontend pages for proposing skincare
routines based on skin state, product compatibility, grooming schedule,
and recent history.

Backend (routines.py):
- POST /routines/suggest — single AM/PM routine for a date
- POST /routines/suggest-batch — AM+PM plan for up to 14 days
- Prompt context: skin snapshot, grooming schedule, 7-day history,
  filtered product list with effects/incompatibilities/context rules
- Respects retinoid frequency limits, acid/retinoid separation,
  grooming-aware safe_after_shaving rules

Frontend:
- /routines/suggest page with tab switcher (single / batch)
- Single tab: date + AM/PM + optional notes → generate → preview → save
- Batch tab: date range + notes → collapsible day cards (AM+PM) → save all
- Loading spinner during Gemini calls; product names resolved from map
- "Zaproponuj rutynę AI" button added to routines list page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Piotr Oleszczyk 2026-03-01 00:34:43 +01:00
parent a3b25d5e46
commit 6e7f715ef2
6 changed files with 918 additions and 5 deletions

View file

@ -1,16 +1,19 @@
import { PUBLIC_API_BASE } from '$env/static/public';
import type {
ActiveIngredient,
BatchSuggestion,
GroomingSchedule,
LabResult,
MedicationEntry,
MedicationUsage,
PartOfDay,
Product,
ProductContext,
ProductEffectProfile,
ProductInteraction,
ProductInventory,
Routine,
RoutineSuggestion,
RoutineStep,
SkinConditionSnapshot
} from './types';
@ -130,6 +133,18 @@ export const updateRoutineStep = (stepId: string, body: Record<string, unknown>)
export const deleteRoutineStep = (stepId: string): Promise<void> =>
api.del(`/routines/steps/${stepId}`);
export const suggestRoutine = (body: {
routine_date: string;
part_of_day: PartOfDay;
notes?: string;
}): Promise<RoutineSuggestion> => api.post('/routines/suggest', body);
export const suggestBatch = (body: {
from_date: string;
to_date: string;
notes?: string;
}): Promise<BatchSuggestion> => api.post('/routines/suggest-batch', body);
export const getGroomingSchedule = (): Promise<GroomingSchedule[]> =>
api.get('/routines/grooming-schedule');
export const createGroomingScheduleEntry = (body: Record<string, unknown>): Promise<GroomingSchedule> =>