Commit graph

95 commits

Author SHA1 Message Date
5dd8242985 fix(routines): simplify inventory preference in system prompt 2026-03-04 12:18:07 +01:00
b58fcb1440 feat(api): add tool-calling flow for shopping suggestions
Keep /products/suggest lean by exposing product UUIDs and fetching INCI, safety rules, actives, and usage notes on demand through Gemini function tools. Add conservative fallback behavior for tool roundtrip limits and expand helper tests to cover tool wiring and payload handlers.
2026-03-04 12:05:33 +01:00
558708653c feat(api): expand routines tool-calling to reduce prompt load
Keep the /routines/suggest base context lean by sending only active names and fetching detailed safety, actives, usage notes, and INCI on demand. Add a conservative fallback when tool roundtrip limits are hit to preserve safe outputs instead of failing the request.
2026-03-04 11:52:07 +01:00
cfd2485b7e feat(api): add INCI tool-calling with normalized tool traces
Enable on-demand INCI retrieval in /routines/suggest through Gemini function calling so detailed ingredient data is fetched only when needed. Persist and normalize tool_trace data in AI logs to make function-call behavior directly inspectable via /ai-logs endpoints.
2026-03-04 11:35:19 +01:00
c0eeb0425d fix(routines): include product safety and usage signals in prompts
Expose leave-on behavior, contraindications, safety alerts, and compact usage notes in AVAILABLE PRODUCTS so Gemini can make safer routine decisions with real-world product constraints.
2026-03-04 02:42:16 +01:00
9bbc34ffd2 test(api): fix ruff issues in routine tests 2026-03-04 02:23:19 +01:00
472a3034a0 feat(routines): refine therapeutic and travel-mode prompt rules 2026-03-04 02:22:39 +01:00
a7ad956a62 fix(frontend): correct plural forms for count labels 2026-03-04 01:30:56 +01:00
820d58ea37 feat(routines): enrich single AI suggestions with concise context 2026-03-04 01:22:57 +01:00
083cd055fb chore(backend): exclude dev and editable installs in deploy sync 2026-03-03 23:21:12 +01:00
a27471a19a docs: add commit guidelines to AGENTS.md 2026-03-03 22:07:39 +01:00
88f3642387 test(api): add tests for ai suggestion endpoints and helpers 2026-03-03 22:06:33 +01:00
5ad9b66a21 build(backend): add pytest-cov configuration and report generation 2026-03-03 22:06:24 +01:00
ba1f10d99f refactor(llm): optimize Gemini config profiles for extraction and creativity
Introduces `get_extraction_config` and `get_creative_config` to standardize Gemini API calls.

* Defines explicit config profiles with appropriate `temperature` and `thinking_level` for Gemini 3 Flash.
* Extraction tasks use minimal thinking and temp=0.0 to reduce latency and token usage.
* Creative tasks use low thinking, temp=0.4, and top_p=0.8 to balance naturalness and safety.
* Applies these helpers across products, routines, and skincare endpoints.
* Also updates default model to `gemini-3-flash-preview`.
2026-03-03 21:24:23 +01:00
78df7322a9 refactor(api): remove shopping assistant logic from mcp_server 2026-03-03 20:51:42 +01:00
067e460dd2 chore(frontend): format files with prettier 2026-03-03 20:51:34 +01:00
0e7a39836f refactor(routines): use category and short uuid for recent history representation 2026-03-03 20:29:36 +01:00
28fb74b9bf refactor(routines): translate prompt input keys to english to reduce language switch penalty 2026-03-03 20:24:56 +01:00
9574c91be1 refactor(routines): remove hardcoded grooming actions from system prompt 2026-03-03 20:22:59 +01:00
4627ec70bf refactor(routines): remove examples from inventory management rule to avoid bias 2026-03-03 20:07:13 +01:00
30ebc093bf feat(routines): adjust inventory management prompt to allow opening better suited sealed products 2026-03-03 20:06:38 +01:00
877051cfaf feat(routines): add actives and recent usage tracking to product context 2026-03-03 20:01:39 +01:00
1109d9f397 fix(products): only suggest when real need exists 2026-03-03 19:51:49 +01:00
d1bdfc4993 docs: replace CLAUDE.md with AGENTS.md and add frontend details 2026-03-03 01:27:01 +01:00
098b158b75 feat(frontend): add ESLint and Prettier with Svelte support
- Install eslint, prettier and related plugins
- Add lint and format npm scripts
- Configure eslint.config.js with Svelte + TypeScript rules
- Configure .prettierrc with Svelte plugin
- Fix code to comply with lint rules:
  - Use resolve() for navigation links
  - Use SvelteMap for reactive maps
  - Use writable  instead of  +
  - Remove unused imports and variables

Note: ignoreGoto is set to true due to eslint-plugin-svelte#1327
2026-03-03 01:21:50 +01:00
609995732b feat(routines): add minimize_products option for batch suggestions 2026-03-03 00:50:49 +01:00
40f9a353bb feat(products): add shopping suggestions feature
- Add POST /api/products/suggest endpoint that analyzes skin condition
  and inventory to suggest product types (e.g., 'Salicylic Acid 2% Masque')
- Add MCP tool get_shopping_suggestions() for MCP clients
- Add 'Suggest' button to Products page in frontend
- Add /products/suggest page with suggestion cards
- Include product type, key ingredients, target concerns, why_needed,
  recommended_time, and frequency in suggestions
- Fix stock logic: sealed products now count as available inventory
- Add legend to clarify ✓ (in stock) vs ✗ (not in stock) markers
2026-03-02 22:38:08 +01:00
389ca5ffdc fix(backend): resolve ty check errors across api, mcp, and lifespan typing 2026-03-02 15:51:14 +01:00
679e4e81f4 feat(frontend): responsive design for mobile (RWD)
- Layout: mobile hamburger + drawer nav (backdrop button + sibling nav),
  desktop sidebar hidden on small screens, p-4 md:p-8 main padding
- Products: card list view on mobile, flex-wrap filters
- Lab results: card list view on mobile
- ProductForm: responsive grids (grid-cols-1 sm:grid-cols-2), skin
  profile checkboxes 2→3 cols, active ingredient row restructured
  (name+✕ in flex row, percent/strength/irritation in 3-col grid),
  section headers stack on mobile
- Skin snapshots: date+icons on one row, badges on separate row below
- Product [id] header: back link stacked above title, redundant badge removed
- Routines header: flex-col on mobile, sm:flex-row

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:35:25 +01:00
c85ca355df refactor(routines): streamline suggest prompt — merge inventory context, add leaving_home SPF hint
- Remove _build_inventory_context; fold pao_months into DOSTĘPNE PRODUKTY entries
- Remove "Otwarte równolegle" duplicate section from prompt
- Rename OSTATNIE RUTYNY (7 dni) → OSTATNIE RUTYNY
- Add _build_day_context and SuggestRoutineRequest.leaving_home (optional bool)
- System prompt: replace unconditional PAO rule with conditional; add SPF factor
  selection logic based on KONTEKST DNIA leaving_home value
- Frontend: leaving_home checkbox (AM only) + i18n keys pl/en

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 23:47:54 +01:00
258b8c4330 refactor(routines): use SQLAlchemy is_(False) for product filters 2026-03-01 23:23:04 +01:00
d3bd2ff30d feat(skincare): allow HEIC/HEIF uploads in skin analysis 2026-03-01 23:23:04 +01:00
f1acfa21fc feat(routines): add inventory-aware product selection rules 2026-03-01 22:15:47 +01:00
914c6087bd fix(products): work around Gemini int-enum schema rejection in parse-text
Gemini API rejects int-valued enums (StrengthLevel) in response_schema,
raising a validation error before any request is sent. Fix by introducing
AIActiveIngredient (inherits ActiveIngredient, overrides strength_level and
irritation_potential as Optional[int]) and ProductParseLLMResponse used only
as the Gemini schema. The two-step validation converts ints back to StrengthLevel
via Pydantic coercion. Adds a test covering the numeric strength level path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 22:00:48 +01:00
921fe3ef61 fix(frontend): pick freshest skin snapshot on dashboard 2026-03-01 21:51:07 +01:00
49c304d06f fix(routines): use system prompt for suggest and dedupe rules 2026-03-01 21:45:31 +01:00
cc657998e8 fix(llm): switch from thinking_budget to thinking_level=LOW for Gemini 3
gemini-flash-latest resolves to gemini-3-flash-preview which uses
thinking_level instead of the legacy thinking_budget (mixing both
returns HTTP 400). Use LOW to reduce thinking overhead while keeping
basic reasoning, replacing the now-incompatible thinking_budget=0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 20:15:49 +01:00
ada5f2a93b fix(llm): disable Gemini thinking to prevent MAX_TOKENS on structured output
Gemini 2.5 Flash (gemini-flash-latest) enables thinking by default.
Thinking tokens count toward max_output_tokens, leaving ~150 tokens for
actual JSON output and causing MAX_TOKENS truncation. Disable thinking
centrally in call_gemini via ThinkingConfig(thinking_budget=0).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 20:12:31 +01:00
092fd87606 fix(llm): log and handle non-STOP finish_reason from Gemini
When Gemini stops generation early (e.g. due to safety filters or
thinking-model quirks), finish_reason != STOP but no exception is raised,
causing the caller to receive truncated JSON and a confusing 502 "invalid
JSON" error. Now:
- finish_reason is extracted from candidates[0] and stored in ai_call_logs
- any non-STOP finish_reason raises HTTP 502 with a clear message
- Alembic migration adds the finish_reason column to ai_call_logs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 20:08:22 +01:00
18683925a1 fix(frontend): use /api proxy for skin photo upload in browser context
analyzeSkinPhotos was hardcoding PUBLIC_API_BASE, causing browser-side
requests to hit localhost:8000 directly instead of going through nginx.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 20:01:16 +01:00
17eaa5d1bd fix(frontend): add missing priorities field to skin snapshots UI
priorities was present in the model, API, and LLM prompt but never
surfaced in the frontend — add it to create/edit forms, read view,
AI photo pre-fill, and page.server.ts actions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 19:58:38 +01:00
75ef1bca56 feat(routines): add minoxidil beard/mustache option to routine suggestions
- Add include_minoxidil_beard flag to SuggestRoutineRequest and SuggestBatchRequest
- Detect minoxidil products by scanning name, brand, INCI and actives; pass them
  to the LLM even though they are medications
- Inject CELE UŻYTKOWNIKA context block into prompts when flag is enabled
- Add _build_objectives_context() returning empty string when flag is off
- Add call_gemini() helper that centralises Gemini API calls and logs every
  request/response to a new ai_call_logs table (AICallLog model + /ai-logs router)
- Nginx: raise client_max_body_size to 16 MB for photo uploads

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 19:46:07 +01:00
3aa03b412b feat(frontend): group product selector by category in routine step forms
Products in the Add/Edit step dropdowns are now grouped by category
(Cleanser → Serum → Moisturizer → …) using SelectGroup/SelectGroupHeading,
and sorted alphabetically by brand then name within each group.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 18:22:51 +01:00
78c67b6179 fix(backend): include steps in list_routines response
Batch-load all routine steps in a single query and attach them to each
routine dict, mirroring the detail endpoint pattern. Fixes "0 steps"
shown on the routines list page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 17:39:33 +01:00
d4e3040674 fix(frontend): fix step numbering and client-side API base URL
- Step numbers now use each-block index (i+1) instead of order_index+1,
  fixing display when order_index starts from 1 in existing data
- api.ts: browser-side requests use /api (nginx proxy) instead of
  PUBLIC_API_BASE (localhost:8000), fixing PATCH/client calls on remote hosts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 17:34:00 +01:00
5cb44b2c65 fix(backend): apply black/isort formatting and fix ruff noqa annotations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 17:27:07 +01:00
4b0fedde35 feat(frontend): add drag-and-drop reordering and inline editing for routine steps
- Install svelte-dnd-action v0.9.69
- Use dragHandleZone + dragHandle for per-step ⋮⋮ drag handles
- PATCH only steps whose order_index changed after a drop
- Inline edit mode (✎ button) expands step in-place: product steps show product/dose/region selects; action steps show action_type/notes
- DnD disabled while a step is being edited

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 17:21:59 +01:00
5e2536138b fix(deploy): suppress prepare script noise with --ignore-scripts
svelte-kit sync runs as a prepare hook but svelte-kit is a devDep,
not installed during prod install — add --ignore-scripts to silence it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 13:57:46 +01:00
91bc9e86d7 fix(deploy): install frontend prod deps on server after deploy
adapter-node bundles the SvelteKit framework but leaves package.json
`dependencies` (clsx, bits-ui, etc.) external — they must be present in
node_modules on the server at runtime.

- deploy.sh: rsync package.json + pnpm-lock.yaml, run pnpm install --prod
- DEPLOYMENT.md: add pnpm to server setup with explanation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 13:56:28 +01:00
3428885aaa docs: add deploy.sh and rewrite DEPLOYMENT.md for local-build workflow
- Add deploy.sh: builds frontend locally, rsyncs build/ to server,
  restarts services via passwordless sudo
- DEPLOYMENT.md: remove pnpm build from server setup (frontend is never
  built on the LXC — esbuild hangs on low-resource containers), add rsync
  to apt packages, document deploy.sh setup (SSH config, sudoers), replace
  manual update steps with ./deploy.sh invocation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 13:51:51 +01:00