Files
turf_saas/prompts_llm.py
2026-04-25 17:18:43 +02:00

291 lines
8.8 KiB
Python

#!/usr/bin/env python3
"""
Prompts LLM Centralisés - Turf Scraper
"""
import os
TURF_DB_SCHEMA = """
Tables disponibles dans turf.db:
1. predictions
- id (INTEGER PRIMARY KEY)
- date (TEXT) - format YYYY-MM-DD
- race_name (TEXT) - ex: "Quinté+"
- race_hippodrome (TEXT) - ex: "Vincennes"
- race_time (TEXT) - ex: "13:55"
- horse_number (INTEGER)
- horse_name (TEXT)
- odds (REAL) - cote
- prediction_rank (INTEGER) - position prédite (1-5)
- source (TEXT) - origine du prono
2. pmu_courses (table des courses)
- id (INTEGER PRIMARY KEY)
- date_programme (TEXT) - YYYY-MM-DD
- num_reunion (INTEGER)
- num_course (INTEGER)
- libelle (TEXT) - nom de la course
- libelle_court (TEXT)
- discipline (TEXT) - PLAT, TROT, ATTELE, MONTE
- distance (INTEGER)
- heure_depart_str (TEXT) - ex: "13:55"
3. pmu_partants (table des partants/chevaux)
- id (INTEGER PRIMARY KEY)
- date_programme (TEXT) - YYYY-MM-DD
- num_reunion (INTEGER)
- num_course (INTEGER)
- num_pmu (INTEGER) - numéro du cheval
- nom (TEXT) - nom du cheval
- driver (TEXT) - jockey
- entraineur (TEXT)
- cote_direct (REAL) - cote
- ordre_arrivee (INTEGER) - position finale (0 = pas couru)
- favoris (INTEGER) - 1 si favori
- tx_victoire (REAL) - taux de victoire %
- tx_place (REAL) - taux podium %
- forme_recente (REAL)
4. odds_history
- id (INTEGER PRIMARY KEY)
- date (TEXT)
- id_race (TEXT)
- scraped_at (TEXT)
- odds_json (TEXT) - cotes au moment X
"""
SAMPLE_DATA = """
Exemples de données réelles (2026-03-26):
- Hippodrome: CHANTILLY
- Course: PRIX DE LA JOURNEE DES PLANTES
- Type: PLAT
- Partants: TORTISAMBERT (3) @ 4.5, WIT (8) @ 7.1, BIN ZARAK (7) @ 12.7
- Résultat: TORTISAMBERT 1er, WIT 2ème, BIN ZARAK 3ème
"""
SYSTEM_PROMPT = """Tu es un expert en paris hippiques et turf français.
Tu as accès à une base de données SQLite (turf.db) contenant:
- Prédictions de pronostics (table: predictions)
- Résultats de courses PMU (table: pmu_partants)
- Historique des cotes (table: odds_history)
- Statistiques de performance (table: performance_stats)
{schema}
Règles importantes:
1. Tu génères ONLY des requêtes SQL SELECT (jamais INSERT/UPDATE/DELETE)
2. Les dates sont au format YYYY-MM-DD (ex: 2026-03-26)
3. Le taux de réussite se calcule: (victoires / total) * 100
4. Le ROI se calcule: (gains misés - mises) / mises * 100
5. Un cheval "placé" est sur le podium (positions 1, 2 ou 3)
6. Les positions 0 = pas encore couru
Réponds en français. Sois précis et concis."""
SQL_GENERATION_PROMPT = """
Génère une requête SQL SQLite pour répondre à cette question.
Question: {question}
Contraintes:
- ONLY SELECT queries (pas de INSERT/UPDATE/DELETE)
- Utilise les noms de colonnes exactes du schéma fourni
- Retourne uniquement le SQL, pas d'explication
- Si impossible, retourne "IMPOSSIBLE: [raison]"
Exemples de requêtes valides:
Q: "taux de réussite des favoris"
SQL: SELECT
AVG(CASE WHEN position = 1 THEN 100.0 ELSE 0.0 END) as win_rate,
AVG(CASE WHEN position IN (1,2,3) THEN 100.0 ELSE 0.0 END) as podium_rate,
COUNT(*) as total_races
FROM pmu_partants
WHERE numero IN (1,2,3)
AND date_armee >= date('now', '-30 days')
AND position > 0
Q: "meilleurs jockeys par victoires"
SQL: SELECT driver, COUNT(*) as wins,
AVG(CASE WHEN position IN (1,2,3) THEN 100.0 ELSE 0.0 END) as podium_rate,
AVG(position) as avg_position
FROM pmu_partants
WHERE position = 1
AND date_armee >= date('now', '-30 days')
GROUP BY driver
ORDER BY wins DESC
LIMIT 10
Q: "performances du cheval TORTISAMBERT"
SQL: SELECT * FROM performance_stats WHERE horse_name LIKE '%TORTISAMBERT%'
Q: "{question}"
SQL:"""
CONVERSATION_PROMPT = """
Historique de la conversation:
{history}
Dernière question: {question}
Analyse cette question en tenant compte du contexte précédent.
Si la question fait référence à un élément de l'historique, utilise-le.
Si la question est vague, fournis une réponse utile basée sur les données disponibles.
Contexte DB:
- predictions: tes prédictions
- pmu_partants: résultats réels
- odds_history: évolution des cotes
Réponds de façon conversationnelle en français."""
REPORT_PROMPTS = {
"daily": """
Génère un rapport quotidien de performance pour la date {date}.
Inclure:
1. Nombre de courses aujourd'hui
2. Résultats (positions des partants)
3. Taux de réussite des prédictions
4. ROI du jour
5. Meilleure cote réalisée
Format: Markdown français concis.
""",
"weekly": """
Génère un rapport hebdomadaire pour la semaine du {start_date} au {end_date}.
Inclure:
1. Total courses, paris, gains
2. Taux de réussite global
3. Meilleurs jockeys/chiens cette semaine
4. Évolution vs semaine précédente
5. Recommandations
Format: Markdown français concis.
""",
"monthly": """
Génère un rapport mensuel pour {month} {year}.
Inclure:
1. Bilan全局 (courses, paris, gains, ROI)
2. Meilleures performances par hippodrome
3. Trends (amélioration/détérioration)
4. Statistiques détaillées
Format: Markdown français concis.
"""
}
SUGGESTIONS_PROMPT = """
Basé sur les données disponibles dans turf.db, génère 5 suggestions de questions
que l'utilisateur pourrait poser.
Les suggestions doivent couvrir différents aspects:
- Statistiques de performance
- Analyse de courses/chevaux spécifiques
- Historique et tendances
- ROI et gains
Retourne SEULEMENT une liste de questions, une par ligne, sans numérotation."""
KEYWORD_PATTERNS = {
"favoris": """
SELECT
AVG(CASE WHEN ordre_arrivee = 1 THEN 100.0 ELSE 0.0 END) as win_rate,
AVG(CASE WHEN ordre_arrivee IN (1,2,3) THEN 100.0 ELSE 0.0 END) as podium_rate,
COUNT(*) as total_races
FROM pmu_partants
WHERE favoris = 1 AND ordre_arrivee > 0
AND date_programme >= date('now', '-7 days')""",
"jockeys": """
SELECT driver, COUNT(*) as wins,
AVG(CASE WHEN ordre_arrivee IN (1,2,3) THEN 100.0 ELSE 0.0 END) as podium_rate,
AVG(ordre_arrivee) as avg_position
FROM pmu_partants
WHERE ordre_arrivee = 1 AND date_programme >= date('now', '-30 days')
GROUP BY driver ORDER BY wins DESC LIMIT 10""",
"entraineurs": """
SELECT entraineur, COUNT(*) as wins,
AVG(CASE WHEN ordre_arrivee IN (1,2,3) THEN 100.0 ELSE 0.0 END) as podium_rate
FROM pmu_partants
WHERE ordre_arrivee = 1 AND date_programme >= date('now', '-30 days')
GROUP BY entraineur ORDER BY wins DESC LIMIT 10""",
"programme": """
SELECT c.id, c.num_reunion, c.num_course, c.libelle, c.discipline, c.distance, c.heure_depart_str,
COUNT(p.id) as partants
FROM pmu_courses c
LEFT JOIN pmu_partants p ON c.date_programme = p.date_programme
AND c.num_reunion = p.num_reunion AND c.num_course = p.num_course
WHERE c.date_programme = date('now')
GROUP BY c.id
ORDER BY c.num_reunion, c.num_course""",
"resultats": """
SELECT p.nom as cheval, p.num_pmu as numero, p.ordre_arrivee as position,
p.cote_direct as cote, p.driver, c.libelle as course
FROM pmu_partants p
JOIN pmu_courses c ON p.date_programme = c.date_programme
AND p.num_reunion = c.num_reunion AND p.num_course = c.num_course
WHERE p.date_programme = date('now', '-1 day')
AND p.ordre_arrivee > 0
ORDER BY c.num_reunion, c.num_course, p.ordre_arrivee""",
"gagnants": """
SELECT p.nom as cheval, p.cote_direct as cote, c.libelle as course, p.date_programme
FROM pmu_partants p
JOIN pmu_courses c ON p.date_programme = c.date_programme
AND p.num_reunion = c.num_reunion AND p.num_course = c.num_course
WHERE p.ordre_arrivee = 1 AND p.cote_direct > 0
ORDER BY p.date_programme DESC
LIMIT 10""",
"cote": """
SELECT p.nom as cheval, p.cote_direct as cote_initiale,
p.ordre_arrivee as position, p.date_programme
FROM pmu_partants p
WHERE p.date_programme >= date('now', '-7 days')
AND p.ordre_arrivee > 0
ORDER BY p.date_programme DESC""",
}
def get_system_prompt() -> str:
"""Retourne le prompt système complet"""
return SYSTEM_PROMPT.format(schema=TURF_DB_SCHEMA)
def get_sql_prompt(question: str) -> str:
"""Retourne le prompt pour génération SQL"""
return SQL_GENERATION_PROMPT.format(question=question)
def get_conversation_prompt(question: str, history: str = "") -> str:
"""Retourne le prompt pour conversation"""
if history:
return CONVERSATION_PROMPT.format(question=question, history=history)
return f"Question: {question}\n\n{get_sql_prompt(question)}"
def get_report_prompt(report_type: str, **kwargs) -> str:
"""Retourne le prompt pour un rapport"""
template = REPORT_PROMPTS.get(report_type, "")
return template.format(**kwargs)
def get_suggestions_prompt() -> str:
"""Retourne le prompt pour suggestions"""
return SUGGESTIONS_PROMPT
def get_keyword_sql(question: str) -> str | None:
"""Retourne SQL basé sur mots-clés (fallback)"""
q = question.lower()
for keyword, sql in KEYWORD_PATTERNS.items():
if keyword in q:
return sql
return None