Files
turf_saas/POD/Intelligence/ML_Predictions_SaaS.md
DevOps Engineer 0492f06bfd docs(HRT-96): Note Intelligence ML + documentation API v1 finale
- Création POD/Intelligence/ML_Predictions_SaaS.md : architecture ML complète,
  flow ml_predictions_cache → ml_feedback_saas → paris → ROI dashboard,
  schéma données/jointures, décision duplication vs modification turf_scraper,
  documentation des 4 stratégies XGBoost, idempotence, usage CLI
- Mise à jour DOCUMENTATION.md : ajout section Turf SaaS API v1 complète
  avec tous les endpoints documentés dont /api/v1/roi/* et /api/v1/ml/feedback/*
  (HRT-92 ROI backend + HRT-93 ML feedback loop)

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-30 21:28:52 +02:00

340 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Note Intelligence — Système ML Prédictions dans turf_saas
**Date de création** : 2026-04-30
**Auteur** : IngenieurDev (H3R7Tech)
**Ticket de référence** : HRT-96 (sprint ML SaaS — HRT-90)
**Scope** : `/home/h3r7/turf_saas/` — AUCUNE modification de `/home/h3r7/turf_scraper/`
---
## 1. Contexte & Décision architecturale
### 1.1 Deux systèmes, deux DB
H3R7Tech exploite deux dépôts séparés :
| Dépôt | Rôle | Base de données |
|---|---|---|
| `/home/h3r7/turf_scraper/` | Scraping PMU + entraînement XGBoost | `turf.db` |
| `/home/h3r7/turf_saas/` | SaaS utilisateurs + API v1 + dashboard | `turf_saas.db` |
### 1.2 Décision de duplication (vs modification turf_scraper)
**Choix : dupliquer les tables et scripts ML dans turf_saas.db, sans toucher à turf_scraper.**
Justification :
- `turf_scraper` est la source de vérité du scraping PMU et des modèles XGBoost — toute modification risque de casser la chaîne de collecte de données.
- `turf_saas` doit fonctionner de manière autonome, avec ses propres utilisateurs, subscriptions et données.
- La table `ml_predictions_cache` est *pré-peuplée* dans `turf_saas.db` par un processus de synchronisation (scheduler ou copie périodique depuis `turf.db`).
- Le feedback loop (`ml_feedback_saas.py`) écrit dans `paris` de `turf_saas.db` uniquement.
---
## 2. Architecture du système ML dans turf_saas
### 2.1 Vue d'ensemble du flow
```
[turf_scraper/turf.db]
└── ml_predictions_cache (XGBoost v1)
│ [sync périodique / scheduler]
[turf_saas/turf_saas.db]
├── ml_predictions_cache ← prédictions XGBoost importées
├── pmu_partants ← données courses PMU
├── pmu_rapports ← dividendes réels PMU
├── paris ← paris virtuels ML (ml_feedback_saas.py)
└── API v1 ──┬── GET /api/v1/predictions/* (lecture ml_predictions_cache)
├── GET /api/v1/roi/by-model (jointure paris + rapports)
├── POST /api/v1/ml/feedback/run (déclenche ml_feedback_saas)
└── GET /api/v1/ml/feedback/stats (stats par stratégie)
[dashboard_saas.html]
Section "Performance & ROI"
Chart.js — ROI par modèle / évolution
```
### 2.2 Table `ml_predictions_cache` (turf_saas.db)
Table centrale du système ML. Contient les prédictions XGBoost pour chaque cheval/course.
| Colonne | Type | Description |
|---|---|---|
| `date` | TEXT | Date de la course (YYYY-MM-DD) |
| `num_reunion` | INTEGER | Numéro de réunion |
| `num_course` | INTEGER | Numéro de course |
| `horse_name` | TEXT | Nom du cheval |
| `horse_number` | INTEGER | Numéro du cheval |
| `odds` | REAL | Cote au moment de la prédiction |
| `prob_top1` | REAL | Probabilité XGBoost de finir 1er |
| `prob_top3` | REAL | Probabilité XGBoost de finir top 3 |
| `ml_score` | REAL | Score ML composite (0100) |
| `recommendation` | TEXT | `top1` / `top3` / `value_bet` |
| `is_value_bet` | INTEGER | 1 si value bet détecté |
| `is_outlier` | INTEGER | 1 si outlier de cote |
| `race_label` | TEXT | Ex: `R1C3` |
| `model_version` | TEXT | Version du modèle (ex: `xgboost_v1`) |
| `risque_label` | TEXT | Niveau de risque (`low`/`neutral`/`high`) |
| `risque_score` | INTEGER | Score risque (0100) |
**Contrainte d'unicité** : `(date, num_reunion, num_course, horse_name)` — garantit l'idempotence des imports.
**Volume actuel** : ~1 000 entrées (2 dates de courses).
---
## 3. Feedback Loop ML — `ml_feedback_saas.py`
### 3.1 Rôle
Script Python autonome qui :
1. Lit les prédictions XGBoost dans `ml_predictions_cache` de `turf_saas.db`
2. Génère des paris virtuels selon 4 stratégies XGBoost
3. Insère les paris dans la table `paris` de `turf_saas.db`
4. Est **idempotent** : ne duplique pas les paris existants
### 3.2 Stratégies supportées
| Stratégie | Type pari | Condition sélection | Mise |
|---|---|---|---|
| `xgboost_sg` | `simple_gagnant` | top 1 ML par course, `ml_score >= 70` | 1€ |
| `xgboost_value` | `simple_gagnant` | `is_value_bet = 1` | 1€ |
| `xgboost_sp` | `simple_place` | top 1 ML par course, `ml_score >= 50` | 1€ |
| `xgboost_2sur4` | `deux_sur_quatre` | top 4 ML par course, 6 combos générés | 6€ (1€/combo) |
### 3.3 Schéma d'idempotence
```python
# Vérifie avant insertion
SELECT id FROM paris
WHERE date_course = ?
AND source_reco = ? # ex: 'xgboost_sg'
AND type_pari = ?
AND numero1 = ?
AND race_label = ?
```
Si le pari existe déjà → skip (aucune duplication).
### 3.4 Table `paris` — colonnes clés pour le ML
| Colonne | Valeur ML |
|---|---|
| `source_reco` | `xgboost_sg` / `xgboost_value` / `xgboost_sp` / `xgboost_2sur4` |
| `model_source` | `xgboost_v1` (héritée de ml_predictions_cache) |
| `type_pari` | `simple_gagnant` / `simple_place` / `deux_sur_quatre` |
| `statut` | `EN_ATTENTE``GAGNE` / `PERDU` (mise à jour par update_paris_results.py) |
| `gain` | Dividende réel × mise (depuis pmu_rapports) |
### 3.5 Usage CLI
```bash
# Traitement du jour
python3 ml_feedback_saas.py
# Date spécifique
python3 ml_feedback_saas.py --date 2026-04-29
# Backfill
python3 ml_feedback_saas.py --backfill 2026-04-20
```
**Différence avec `turf_scraper/ml_feedback.py`** :
- `DB_PATH` = `/home/h3r7/turf_saas/turf_saas.db` (PAS `/home/h3r7/turf_scraper/turf.db`)
- Logs dans `/home/h3r7/turf_saas/logs/`
- AUCUNE référence à `turf_scraper`
---
## 4. API ROI — `/api/v1/roi/*`
### 4.1 Route principale
**`GET /api/v1/roi/by-model`** — Calcul du ROI par modèle/stratégie
Jointures SQL :
```sql
-- paris ←→ pmu_partants (via race_label + date + numero)
-- paris ←→ pmu_rapports (dividendes réels)
SELECT
p.source_reco AS model_source,
COUNT(p.id) AS nb_paris,
SUM(p.mise) AS mise_totale,
SUM(p.gain) AS gain_total,
(SUM(p.gain) - SUM(p.mise)) / SUM(p.mise) * 100 AS roi_pct,
COUNT(CASE WHEN p.statut='GAGNE' THEN 1 END) * 100.0 / COUNT(p.id) AS win_rate
FROM paris p
WHERE p.date_course BETWEEN :start AND :end
AND (:strategy IS NULL OR p.source_reco = :strategy)
GROUP BY p.source_reco
```
**Paramètres query** :
- `?strategy=xgboost_sg` — filtrer par stratégie (optionnel)
- `?days=30` — fenêtre temporelle en jours (défaut : 30, max : 365)
**Réponse JSON** :
```json
{
"period": {"start": "2026-04-01", "end": "2026-04-30", "days": 30},
"models": [
{
"model_source": "xgboost_sg",
"nb_paris": 42,
"mise": 42.0,
"gain": 51.3,
"roi_pct": 22.1,
"win_rate": 28.6
}
]
}
```
**Accès plan** :
- `free` : 1 stratégie max
- `premium` : complet
- `pro` : complet + historique illimité
### 4.2 Blueprint `api_v1/routes/roi.py`
Enregistré dans `api_v1/__init__.py` avec :
```python
from .routes.roi import roi_bp
app.register_blueprint(roi_bp)
```
---
## 5. API ML Feedback — `/api/v1/ml/feedback/*`
### 5.1 Routes
| Méthode | Path | Auth | Description |
|---|---|---|---|
| `POST` | `/api/v1/ml/feedback/run` | Admin | Déclenche `ml_feedback_saas.py` manuellement |
| `GET` | `/api/v1/ml/feedback/stats` | Premium+ | Stats paris par stratégie XGBoost |
### 5.2 `POST /api/v1/ml/feedback/run`
- Réservé aux admins (token admin requis)
- Déclenche le script `ml_feedback_saas.py` en subprocess
- Corps optionnel : `{"date": "2026-04-29"}` ou `{"backfill": "2026-04-20"}`
### 5.3 `GET /api/v1/ml/feedback/stats`
Retourne les statistiques agrégées par stratégie :
```json
{
"stats": [
{
"source_reco": "xgboost_sg",
"nb_paris": 42,
"nb_gagnes": 12,
"win_rate_pct": 28.6,
"mise_totale": 42.0,
"gain_total": 51.3,
"roi_pct": 22.1
}
],
"last_run": "2026-04-29T18:30:00"
}
```
### 5.4 Blueprint `api_v1/routes/ml_feedback.py`
Enregistré dans `api_v1/__init__.py` avec :
```python
from .routes.ml_feedback import ml_feedback_bp
app.register_blueprint(ml_feedback_bp)
```
---
## 6. Jointures de données — Schéma complet
```
ml_predictions_cache
date, num_reunion, num_course, horse_name, horse_number
ml_score, recommendation, is_value_bet
race_label, model_version
│ [ml_feedback_saas.py]
paris
date_course, race_label, numero1
source_reco (= stratégie XGBoost)
model_source (= xgboost_v1)
type_pari, mise, statut, gain
├──── JOIN pmu_partants ──── date_programme + num_reunion + num_course + num_pmu
│ ordre_arrivee (résultat réel)
└──── JOIN pmu_rapports ──── date_programme + num_reunion + num_course + type_pari
dividende_euro (gain réel calculé)
```
---
## 7. Dashboard SaaS — Section ROI
Le dashboard `dashboard_saas.html` intègre une section **"Performance & ROI"** (implémentée dans HRT-94) :
- Graphique ROI par `model_source` (histogramme Chart.js)
- Évolution ROI dans le temps (line chart, 7j/30j/90j)
- Tableau : `model_source | nb paris | mise | gain | ROI% | win_rate%`
- Filtre dropdown par stratégie
- Gating plan : Free = 1 stratégie, Premium/Pro = complet
Appel API dashboard :
```javascript
fetch('/api/v1/roi/by-model?days=30')
```
---
## 8. Points d'attention & limites
1. **Données ML limitées** : actuellement 1 000 prédictions sur 2 dates (2026-04-24 et 2026-04-25). La pertinence du ROI augmentera avec le volume de données.
2. **Pas de paris XGBoost actifs** : la table `paris` contient des paris `manual`, `scoring_v2`, `canalturf` mais pas encore de paris `xgboost_*`. HRT-93 (ml_feedback_saas.py) doit être complété et exécuté.
3. **Modèle unique** : `model_version = 'xgboost_v1'`. L'évolution vers des versions de modèle multiples est prévue dans la roadmap.
4. **Sync turf_scraper → turf_saas** : le mécanisme de synchronisation de `ml_predictions_cache` n'est pas encore documenté formellement. À documenter dans une prochaine Note Intelligence.
5. **update_paris_results.py** : script de mise à jour des statuts paris (`EN_ATTENTE → GAGNE/PERDU`) à partir de `pmu_rapports` — dépendance critique pour le calcul du ROI réel.
---
## 9. Fichiers clés
| Fichier | Rôle |
|---|---|
| `turf_saas.db` | Base de données principale SaaS |
| `ml_feedback_saas.py` | Feedback loop ML (à créer — HRT-93) |
| `api_v1/routes/roi.py` | Routes API ROI (à créer — HRT-92) |
| `api_v1/routes/ml_feedback.py` | Routes API feedback (à créer — HRT-93) |
| `api_v1/__init__.py` | Enregistrement des blueprints |
| `dashboard_saas.html` | Dashboard SaaS avec section ROI |
| `update_paris_results.py` | MAJ statuts paris depuis résultats PMU |
| `scoring_v2.py` | Scoring engine (stratégie scoring_v2) |
---
## 10. Références tickets
| Ticket | Description | Statut |
|---|---|---|
| HRT-90 | Orchestration ML SaaS (parent) | blocked |
| HRT-92 | Backend: API ROI par modèle | in_progress |
| HRT-93 | ML feedback loop ml_feedback_saas | in_progress |
| HRT-94 | Frontend: Dashboard ROI | in_progress |
| HRT-95 | QA: Tests end-to-end ML + ROI | in_progress |
| HRT-96 | Note Intelligence ML + documentation (ce ticket) | in_progress |