You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Shot analysis via POST /api/shots/analyze-llm already sends profile JSON + local analysis data to Gemini and returns structured markdown with 5 sections, including "Section 4: Profile Recommendations." However, these recommendations are currently text-only — users must manually interpret and apply them. This issue bridges the gap by extracting structured, actionable recommendations and letting users selectively apply them through the profile editing pipeline introduced in #257.
Current State
Backend
Analysis endpoint (POST /api/shots/analyze-llm in shots.py) sends profile structure (stages, variables, triggers) + local algorithmic analysis to Gemini
Prompt (prompt_builder.py) includes PROFILING_KNOWLEDGE with detailed OEPF specification knowledge
Response is parsed by parseStructuredAnalysis() on the frontend into 5 titled sections
No structured recommendation format exists — recommendations are embedded in natural language markdown
Frontend
ExpertAnalysisView.tsx renders the 5 analysis sections as styled cards — fully read-only
ShotHistoryView.tsx hosts the analysis tabs (Replay/Compare/Analyze)
No mechanism to extract or apply individual recommendations
Profile Format
Profiles follow OEPF format with patchable fields:
temperature (°C)
final_weight (grams)
variables[] (adjustable values referenced by $key in stage dynamics)
Info variables (info_* prefix) — grind, dose recommendations
Implementation Plan
Backend
New endpoint: POST /api/shots/analyze-recommendations
Accepts same inputs as analyze-llm (profile name, shot date, shot filename)
Calls Gemini with a modified prompt requesting structured JSON recommendations
Returns the updated profile and a summary of applied changes
AI Prompt Changes
Extend the analysis prompt to request a RECOMMENDATIONS_JSON block alongside existing markdown:
After your analysis, output a fenced block:
```recommendations_json
[{ "category": "...", "field_path": "...", ... }]
- Map each natural-language recommendation to a specific profile field path
- Include confidence level based on how clearly the shot data supports the change
- Mark as `patchable: false` for setup-only changes (grind, dose, technique)
Frontend
New RecommendationSelectionDialog component:
Triggered by "Apply Recommendations" button in ExpertAnalysisView
Checkbox list of all recommendations, grouped by category
Patchable items: checkbox + current → suggested value preview
Non-patchable items: info icon + rationale (no checkbox)
Confidence badges (high/medium/low) with color coding
"Apply Selected" button → calls POST /api/profile/{name}/apply-recommendations
Success: toast with summary, link to view updated profile
Update ExpertAnalysisView.tsx:
Add "Apply Recommendations" button after Section 4
Button disabled if no analysis has been run
Loading state while recommendations are being extracted
Background
Shot analysis via
POST /api/shots/analyze-llmalready sends profile JSON + local analysis data to Gemini and returns structured markdown with 5 sections, including "Section 4: Profile Recommendations." However, these recommendations are currently text-only — users must manually interpret and apply them. This issue bridges the gap by extracting structured, actionable recommendations and letting users selectively apply them through the profile editing pipeline introduced in #257.Current State
Backend
POST /api/shots/analyze-llminshots.py) sends profile structure (stages, variables, triggers) + local algorithmic analysis to Geminiprompt_builder.py) includesPROFILING_KNOWLEDGEwith detailed OEPF specification knowledgeparseStructuredAnalysis()on the frontend into 5 titled sectionsFrontend
ExpertAnalysisView.tsxrenders the 5 analysis sections as styled cards — fully read-onlyShotHistoryView.tsxhosts the analysis tabs (Replay/Compare/Analyze)Profile Format
Profiles follow OEPF format with patchable fields:
temperature(°C)final_weight(grams)variables[](adjustable values referenced by$keyin stage dynamics)info_*prefix) — grind, dose recommendationsImplementation Plan
Backend
New endpoint:
POST /api/shots/analyze-recommendationsanalyze-llm(profile name, shot date, shot filename){ "recommendations": [ { "id": "rec_1", "category": "temperature" | "weight" | "variable" | "grind" | "dose" | "technique", "field_path": "temperature" | "final_weight" | "variables.pressure_1", "current_value": 93.0, "suggested_value": 91.5, "unit": "°C", "rationale": "Reducing temperature by 1.5°C will reduce bitterness...", "confidence": "high" | "medium" | "low", "patchable": true } ], "summary": "3 profile adjustments recommended to improve extraction balance" }patchable: falseand display rationale onlyNew endpoint:
POST /api/profile/{name}/apply-recommendations{ recommendation_ids: string[], recommendations: Recommendation[] }patchable: trueitems matching the provided IDsAI Prompt Changes
RECOMMENDATIONS_JSONblock alongside existing markdown:Frontend
New
RecommendationSelectionDialogcomponent:ExpertAnalysisViewPOST /api/profile/{name}/apply-recommendationsUpdate
ExpertAnalysisView.tsx:Dependencies
PUT /api/profile/{name}/editendpoint is the write path for applying recommendationsanalyze-llmendpoint)Acceptance Criteria
POST /api/shots/analyze-recommendationsreturns structured JSON recommendations with field paths, values, confidence, and rationalePOST /api/profile/{name}/apply-recommendationsbatch-applies selected patchable recommendationsRecommendationSelectionDialogshows grouped, checkable recommendations with current → suggested value previewsKey Files
apps/server/api/routes/shots.pyapps/server/api/routes/profiles.pyapps/server/prompt_builder.pyapps/web/src/components/ExpertAnalysisView.tsxapps/web/src/components/RecommendationSelectionDialog.tsxapps/web/public/locales/*/translation.json