Initial commit: existing turf_saas codebase
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
262
weather_module_v2.py
Executable file
262
weather_module_v2.py
Executable file
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Weather Module v2 - With Database Storage
|
||||
Tracks weather history for performance analysis
|
||||
"""
|
||||
import requests
|
||||
from datetime import datetime
|
||||
import sqlite3
|
||||
|
||||
DB_PATH = "/home/h3r7/turf_scraper/turf.db"
|
||||
|
||||
# Hippodrome coordinates
|
||||
HIPPODROMES = {
|
||||
'auteuil': (48.8718, 2.2525),
|
||||
'chantilly': (49.1939, 2.4744),
|
||||
'deauville': (49.3563, 0.0775),
|
||||
'vincennes': (48.8414, 2.4375),
|
||||
'longchamp': (48.8641, 2.2372),
|
||||
'saint-cloud': (48.8419, 2.1039),
|
||||
'pau': (43.2917, -0.3708),
|
||||
'cagnes-sur-mer': (43.6689, 7.1914),
|
||||
'lyon-parilly': (45.7378, 4.8092),
|
||||
'lyon': (45.7378, 4.8092),
|
||||
'marseille': (43.2964, 5.3695),
|
||||
'cagnes': (43.6689, 7.1914),
|
||||
'le croise larroche': (50.6692, 3.0775),
|
||||
'mons': (50.4547, 3.9522),
|
||||
}
|
||||
|
||||
def init_weather_db():
|
||||
"""Initialize weather table"""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
|
||||
c.execute('''
|
||||
CREATE TABLE IF NOT EXISTS weather (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date TEXT NOT NULL,
|
||||
hippodrome TEXT,
|
||||
temperature REAL,
|
||||
humidity INTEGER,
|
||||
wind_speed REAL,
|
||||
precipitation REAL,
|
||||
weather_code INTEGER,
|
||||
ground_condition TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
''')
|
||||
|
||||
c.execute('''
|
||||
CREATE TABLE IF NOT EXISTS horse_weather_performance (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date TEXT,
|
||||
race_date TEXT,
|
||||
horse_name TEXT,
|
||||
position INTEGER,
|
||||
hippodrome TEXT,
|
||||
temperature REAL,
|
||||
ground_condition TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
''')
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print("Weather tables initialized!")
|
||||
|
||||
def get_weather(hippodrome, date=None):
|
||||
"""Get weather from Open-Meteo API"""
|
||||
hippo_key = hippodrome.lower().strip()
|
||||
|
||||
# Try to find matching hippodrome
|
||||
coords = None
|
||||
for name, coord in HIPPODROMES.items():
|
||||
if name in hippo_key or hippo_key in name:
|
||||
coords = coord
|
||||
break
|
||||
|
||||
if not coords:
|
||||
return {'error': f'Hippodrome non trouvé: {hippodrome}'}
|
||||
|
||||
lat, lon = coords
|
||||
|
||||
url = "https://api.open-meteo.com/v1/forecast"
|
||||
params = {
|
||||
'latitude': lat,
|
||||
'longitude': lon,
|
||||
'current': 'temperature_2m,relative_humidity_2m,precipitation,rain,weather_code,wind_speed_10m',
|
||||
'timezone': 'Europe/Paris'
|
||||
}
|
||||
|
||||
try:
|
||||
r = requests.get(url, params=params, timeout=10)
|
||||
data = r.json()
|
||||
|
||||
if 'current' in data:
|
||||
current = data['current']
|
||||
weather = {
|
||||
'hippodrome': hippodrome,
|
||||
'temperature': current.get('temperature_2m'),
|
||||
'humidity': current.get('relative_humidity_2m'),
|
||||
'precipitation': current.get('precipitation'),
|
||||
'rain': current.get('rain'),
|
||||
'weather_code': current.get('weather_code'),
|
||||
'wind_speed': current.get('wind_speed_10m'),
|
||||
'ground_condition': get_ground_condition(current),
|
||||
'timestamp': datetime.now().isoformat()
|
||||
}
|
||||
return weather
|
||||
|
||||
except Exception as e:
|
||||
return {'error': str(e)}
|
||||
|
||||
return {'error': 'Unknown error'}
|
||||
|
||||
def get_ground_condition(weather_data):
|
||||
"""Determine ground condition"""
|
||||
if isinstance(weather_data, dict):
|
||||
precip = weather_data.get('precipitation', 0)
|
||||
else:
|
||||
precip = 0
|
||||
|
||||
if precip > 10:
|
||||
return 'TRES_LOURD'
|
||||
elif precip > 5:
|
||||
return 'LOURD'
|
||||
elif precip > 1:
|
||||
return 'SOUPLE'
|
||||
else:
|
||||
return 'BON'
|
||||
|
||||
def weather_code_to_desc(code):
|
||||
"""Weather code to description"""
|
||||
codes = {
|
||||
0: "Ciel dégagé", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast",
|
||||
45: "Brouillard", 48: "Brouillard",
|
||||
51: "Bruine légère", 53: "Bruine", 55: "Bruine dense",
|
||||
61: "Pluie légère", 63: "Pluie", 65: "Pluie forte",
|
||||
71: "Neige légère", 73: "Neige", 75: "Neige forte",
|
||||
80: "Averses", 81: "Averses", 82: "Averses fortes",
|
||||
95: "Orage", 96: "Orage grêle",
|
||||
}
|
||||
return codes.get(code, f"Code {code}")
|
||||
|
||||
def save_weather(date, hippodrome, weather):
|
||||
"""Save weather to database"""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
|
||||
c.execute('''
|
||||
INSERT INTO weather (date, hippodrome, temperature, humidity, wind_speed, precipitation, weather_code, ground_condition)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
''', (
|
||||
date,
|
||||
hippodrome,
|
||||
weather.get('temperature'),
|
||||
weather.get('humidity'),
|
||||
weather.get('wind_speed'),
|
||||
weather.get('precipitation'),
|
||||
weather.get('weather_code'),
|
||||
weather.get('ground_condition')
|
||||
))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print(f"Weather saved: {hippodrome} - {weather.get('ground_condition')}")
|
||||
|
||||
def save_horse_weather_performance(date, race_date, horse_name, position, hippodrome, temperature, ground_condition):
|
||||
"""Save horse performance with weather"""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
|
||||
c.execute('''
|
||||
INSERT INTO horse_weather_performance (date, race_date, horse_name, position, hippodrome, temperature, ground_condition)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
''', (date, race_date, horse_name, position, hippodrome, temperature, ground_condition))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def get_horse_weather_stats(horse_name):
|
||||
"""Get horse performance by weather conditions"""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
|
||||
c.execute('''
|
||||
SELECT
|
||||
ground_condition,
|
||||
COUNT(*) as races,
|
||||
SUM(CASE WHEN position <= 3 THEN 1 ELSE 0 END) as podiums,
|
||||
ROUND(CAST(SUM(CASE WHEN position <= 3 THEN 1 ELSE 0 END) AS FLOAT) / COUNT(*) * 100, 1) as podium_rate
|
||||
FROM horse_weather_performance
|
||||
WHERE horse_name = ?
|
||||
GROUP BY ground_condition
|
||||
''', (horse_name,))
|
||||
|
||||
results = c.fetchall()
|
||||
conn.close()
|
||||
|
||||
stats = {}
|
||||
for row in results:
|
||||
stats[row[0]] = {
|
||||
'races': row[1],
|
||||
'podiums': row[2],
|
||||
'podium_rate': row[3]
|
||||
}
|
||||
|
||||
return stats
|
||||
|
||||
def analyze_weather_advantage(horse_name):
|
||||
"""Analyze horse performance by weather"""
|
||||
stats = get_horse_weather_stats(horse_name)
|
||||
|
||||
if not stats:
|
||||
return {'message': 'Pas de données météo pour ce cheval'}
|
||||
|
||||
# Find best ground condition
|
||||
best = None
|
||||
best_rate = 0
|
||||
for condition, data in stats.items():
|
||||
if data['podium_rate'] > best_rate:
|
||||
best_rate = data['podium_rate']
|
||||
best = condition
|
||||
|
||||
return {
|
||||
'horse': horse_name,
|
||||
'best_ground': best,
|
||||
'best_rate': best_rate,
|
||||
'all_conditions': stats
|
||||
}
|
||||
|
||||
# Test
|
||||
if __name__ == "__main__":
|
||||
init_weather_db()
|
||||
|
||||
print("\n" + "="*50)
|
||||
print("WEATHER MODULE v2 - TEST")
|
||||
print("="*50)
|
||||
|
||||
# Get weather for today's races
|
||||
hippodromes = ['Auteuil', 'Vincennes', 'Pau', 'Cagnes-sur-Mer']
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
|
||||
for hippo in hippodromes:
|
||||
w = get_weather(hippo)
|
||||
if 'error' not in w:
|
||||
print(f"\n{hippo}:")
|
||||
print(f" {w.get('temperature')}°C, {w.get('humidity')}%, {w.get('wind_speed')} km/h")
|
||||
print(f" Terrain: {w.get('ground_condition')}")
|
||||
save_weather(today, hippo, w)
|
||||
|
||||
# Test horse weather analysis
|
||||
print("\n" + "="*50)
|
||||
print("HORSE WEATHER ANALYSIS TEST")
|
||||
print("="*50)
|
||||
|
||||
# Save some test data
|
||||
save_horse_weather_performance(today, today, 'PASSIONATA', 1, 'Auteuil', 13, 'BON')
|
||||
save_horse_weather_performance(today, today, 'PASSIONATA', 2, 'Vincennes', 10, 'SOUPLE')
|
||||
|
||||
result = analyze_weather_advantage('PASSIONATA')
|
||||
print(f"\nPASSIONATA: {result}")
|
||||
Reference in New Issue
Block a user