Complete French→English translation across all frontend pages and backend
services — every label, button, header, empty state, toast, and nav item
is now in English. Build verified clean (tsc + vite). No i18n library
added; direct string replacement throughout.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- portfolio_context.py: add _safe_float() helper (converts NaN/Inf → None);
use .squeeze().dropna() on yfinance closes before computing moves;
guard division by checking closes.iloc[-2] != 0
- cycle.py: add _sanitize_floats() recursive sanitizer applied to the full
snapshot before FastAPI serializes it — catches any remaining NaN from
iv_rank, technical indicators, or other sources
Fixes 500 on GET /api/cycle/contexts/{run_id} when yfinance returns NaN
weekend data for portfolio positions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Portfolio context (portfolio_context.py):
- get_open_trades_with_moves(): fetches open trades + 1d/5d yfinance price moves
- get_portfolio_concentration(): counts by asset_class
- build_portfolio_context_block(): formatted prompt block with strict AI instructions
(no double positions, flag contradictions, avoid overweight classes)
AI call logging:
- ai_call_logs table in DB (run_id, call_type, system/user prompt, response, tokens, ms)
- _chat() now accepts log_meta dict → saves call to DB non-blocking after each call
- suggest and score_batch calls pass run_id + call_type for full traceability
auto_cycle.py:
- Builds portfolio context before snapshot and both AI calls
- Context snapshot now includes portfolio_open_positions key
SystemLogs.tsx:
- "Contexte IA" tab gains sub-tabs: Contexte / Appels IA
- AiCallRow: expandable with 3 panes (user prompt / system prompt / response)
shows model, tokens breakdown, duration, call type badge
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>