#!/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