Files
Eurojackpot-Tipp-Generator/scripts/automation/auto_update_and_learn.py
T
cbazzaandClaude Sonnet 4.5 98a74ff2a7 Fix data paths in update automation
- Fixed default data-dir in auto_update_and_learn.py (was pointing to old iCloud path)
- Updated run_update_and_learn.sh to explicitly pass correct data-dir
- Added missing Eurojackpot draw from 2026-01-13 (2-16-27-33-47 + 6-12)
- Now saves data to /Projekte/Eurojackpot/data instead of iCloud

This fixes the issue where updates ran successfully but saved to the wrong location.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-14 11:55:40 +01:00

470 lines
15 KiB
Python

#!/usr/bin/env python3
"""
Automatischer Eurojackpot Update & Learning Workflow
Nach jeder Ziehung:
1. Aktualisiert Daten von API
2. Evaluiert letzte generierte Tipps
3. Real-Time Learning Update
4. Performance-Report
Verwendung:
python auto_update_and_learn.py
Oder als Cronjob (nach Ziehung):
0 21 * * 2,5 cd /path/to/eurojackpot && source venv/bin/activate && python scripts/automation/auto_update_and_learn.py
"""
import sys
import os
from datetime import datetime, timedelta
import json
import pandas as pd
# Path Setup
script_dir = os.path.dirname(os.path.abspath(__file__))
project_dir = os.path.dirname(os.path.dirname(script_dir))
sys.path.insert(0, project_dir)
from scripts.utils.update_from_api import EurojackpotAPIUpdater
from scripts.generators.ultimate_ai_ml_eurojackpot_generator import UltimateAIMLEurojackpotGenerator
from scripts.utils.notifier import EurojackpotNotifier
class AutoUpdateAndLearn:
"""Automatisches Update und Learning System."""
def __init__(self, data_dir: str):
self.data_dir = data_dir
# CSV file is in Eurojackpot/data folder
# data_dir = .../Eurojackpot/data
# We need .../Eurojackpot/data/AlleEurojackpotzahlen.csv
self.data_file = os.path.join(data_dir, "AlleEurojackpotzahlen.csv")
self.tips_dir = os.path.join(data_dir, "generated_tips")
self.reports_dir = os.path.join(data_dir, "performance_reports")
self.learning_log = os.path.join(data_dir, "learning_log.json")
os.makedirs(self.reports_dir, exist_ok=True)
# Initialisiere Notifier
self.notifier = EurojackpotNotifier()
print("🤖 AUTOMATISCHES UPDATE & LEARNING SYSTEM")
print("=" * 70)
def load_learning_log(self) -> dict:
"""Lädt Learning Log."""
if os.path.exists(self.learning_log):
with open(self.learning_log, 'r') as f:
return json.load(f)
return {"updates": []}
def save_learning_log(self, log: dict):
"""Speichert Learning Log."""
with open(self.learning_log, 'w') as f:
json.dump(log, f, indent=2)
def check_for_new_draw(self) -> dict:
"""
Prüft ob neue Ziehung verfügbar ist.
Returns:
Dict mit neuer Ziehung oder None
"""
print("\n🔍 PRÜFE AUF NEUE ZIEHUNG")
print("=" * 70)
log = self.load_learning_log()
# Lade aktuelle Daten
try:
df = pd.read_csv(self.data_file, sep=';')
df['datum'] = pd.to_datetime(df['datum'], format='%Y-%m-%d')
# Sortiere nach Datum absteigend und nimm neueste Ziehung
df = df.sort_values('datum', ascending=False)
latest_draw = df.iloc[0] # Neueste Ziehung
latest_date = latest_draw['datum']
print(f" 📅 Neueste Ziehung in Daten: {latest_date.strftime('%Y-%m-%d')}")
# Prüfe ob schon verarbeitet
if log["updates"]:
last_processed = log["updates"][-1].get("draw_date")
if last_processed == latest_date.strftime('%Y-%m-%d'):
print(f" ⏭️ Bereits verarbeitet")
return None
print(f" ✅ Neue Ziehung gefunden!")
return {
'date': latest_date,
'Z1': int(latest_draw['Z1']),
'Z2': int(latest_draw['Z2']),
'Z3': int(latest_draw['Z3']),
'Z4': int(latest_draw['Z4']),
'Z5': int(latest_draw['Z5']),
'SZ1': int(latest_draw['SZ1']),
'SZ2': int(latest_draw['SZ2'])
}
except Exception as e:
print(f" ❌ Fehler beim Prüfen: {e}")
return None
def update_data(self) -> bool:
"""
Aktualisiert Daten von API.
Returns:
True bei Erfolg
"""
print("\n📥 AKTUALISIERE DATEN VON API")
print("=" * 70)
try:
updater = EurojackpotAPIUpdater(self.data_file)
success = updater.update(api_name='all', create_backup=True)
if success:
print(" ✅ Daten erfolgreich aktualisiert")
else:
print(" ⚠️ Update ohne neue Daten")
return success
except Exception as e:
print(f" ❌ Fehler beim Update: {e}")
return False
def evaluate_tips(self, new_draw: dict) -> dict:
"""
Evaluiert letzte generierte Tipps gegen neue Ziehung.
Args:
new_draw: Dict mit neuer Ziehung
Returns:
Evaluierungs-Ergebnisse
"""
print("\n🎯 EVALUIERE LETZTE TIPPS")
print("=" * 70)
# Finde Tipps-Datei die VOR der Ziehung generiert wurde
if not os.path.exists(self.tips_dir):
print(" ⚠️ Keine Tipps zum Evaluieren")
return {}
tip_files = sorted(
[f for f in os.listdir(self.tips_dir) if f.endswith('.csv')],
reverse=True
)
if not tip_files:
print(" ⚠️ Keine Tipps-Dateien gefunden")
return {}
# Finde Tip-Datei die vor der Ziehung erstellt wurde
draw_date = new_draw['date']
selected_tip_file = None
for tip_file in tip_files:
# Parse Timestamp aus Dateiname: weekly_tips_YYYYMMDD_HHMMSS.csv
try:
parts = tip_file.replace('.csv', '').split('_')
tip_date_str = parts[-2] # YYYYMMDD
tip_date = pd.to_datetime(tip_date_str, format='%Y%m%d')
# Nehme erste Datei die vor der Ziehung war
if tip_date < draw_date:
selected_tip_file = tip_file
break
except:
continue
if not selected_tip_file:
# Fallback: nehme älteste Datei
selected_tip_file = tip_files[-1]
latest_tips_file = os.path.join(self.tips_dir, selected_tip_file)
print(f" 📁 Evaluiere: {selected_tip_file}")
try:
tips_df = pd.read_csv(latest_tips_file)
# Extrahiere gezogene Zahlen
drawn_main = [new_draw[f'Z{i}'] for i in range(1, 6)]
drawn_euro = [new_draw['SZ1'], new_draw['SZ2']]
print(f" 🎲 Gezogene Zahlen: {drawn_main} + Euro {drawn_euro}")
print()
results = []
best_matches = {'main': 0, 'euro': 0, 'tip': None}
for _, tip in tips_df.iterrows():
# Parse Hauptzahlen
main_str = tip['Main_Numbers']
# Handle both formats: "[1, 2, 3]" and "1-2-3"
if main_str.startswith('['):
# Parse Python list format
import ast
tip_main = ast.literal_eval(main_str)
else:
# Parse dash-separated format
tip_main = [int(n) for n in main_str.split('-')]
# Parse Eurozahlen
euro_str = tip['Euro_Numbers']
if euro_str.startswith('['):
import ast
tip_euro = ast.literal_eval(euro_str)
else:
tip_euro = [int(n) for n in euro_str.split('-')]
# Zähle Treffer
main_matches = len(set(tip_main) & set(drawn_main))
euro_matches = len(set(tip_euro) & set(drawn_euro))
total_matches = main_matches + euro_matches
results.append({
'tip_number': tip['Tip_Number'],
'strategy': tip['Strategy'],
'main_matches': main_matches,
'euro_matches': euro_matches,
'total_matches': total_matches
})
# Track best
if total_matches > (best_matches['main'] + best_matches['euro']):
best_matches = {
'main': main_matches,
'euro': euro_matches,
'tip': tip['Tip_Number']
}
# Ausgabe
print(f" {'Tip':<5} {'Strategie':<15} {'Main':<6} {'Euro':<6} {'Gesamt':<8} {'Bewertung'}")
print(" " + "-" * 60)
for r in results:
rating = self._get_match_rating(r['main_matches'], r['euro_matches'])
print(f" #{r['tip_number']:<4} {r['strategy']:<15} "
f"{r['main_matches']:<6} {r['euro_matches']:<6} "
f"{r['total_matches']:<8} {rating}")
print()
print(f" 🏆 Bester Tipp: #{best_matches['tip']} "
f"({best_matches['main']} Main + {best_matches['euro']} Euro)")
return {
'file': tip_files[0],
'results': results,
'best': best_matches,
'avg_main_matches': sum(r['main_matches'] for r in results) / len(results),
'avg_euro_matches': sum(r['euro_matches'] for r in results) / len(results)
}
except Exception as e:
print(f" ❌ Fehler bei Evaluation: {e}")
import traceback
traceback.print_exc()
return {}
def _get_match_rating(self, main: int, euro: int) -> str:
"""Bewertung der Treffer."""
total = main + euro
if main == 5 and euro == 2:
return "🏆 JACKPOT!"
elif main == 5 and euro == 1:
return "💰 Klasse 2"
elif main == 5 and euro == 0:
return "💰 Klasse 3"
elif main == 4 and euro == 2:
return "💰 Klasse 4"
elif main == 4 and euro == 1:
return "💵 Klasse 5"
elif total >= 3:
return "✅ Gut"
elif total >= 2:
return "👍 OK"
else:
return "⚪ Niedrig"
def perform_learning_update(self, new_draw: dict) -> bool:
"""
Führt Real-Time Learning Update durch.
Args:
new_draw: Dict mit neuer Ziehung
Returns:
True bei Erfolg
"""
print("\n🧠 REAL-TIME LEARNING UPDATE")
print("=" * 70)
try:
# Initialisiere Generator
generator = UltimateAIMLEurojackpotGenerator(
self.data_file,
fast_mode=True
)
# Learning Update
generator.real_time_learner.learn_from_result(new_draw)
# Performance Tracking
generator.performance_tracker.evaluate_predictions(new_draw)
print(" ✅ Learning Update durchgeführt")
print(" 📊 Models wurden angepasst")
return True
except Exception as e:
print(f" ❌ Fehler beim Learning: {e}")
return False
def generate_report(self, new_draw: dict, evaluation: dict):
"""Generiert Performance-Report."""
print("\n📊 PERFORMANCE-REPORT")
print("=" * 70)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
report_file = os.path.join(
self.reports_dir,
f"report_{timestamp}.txt"
)
report = []
report.append("=" * 70)
report.append("EUROJACKPOT PERFORMANCE REPORT")
report.append("=" * 70)
report.append(f"Erstellt: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
report.append("")
report.append(f"ZIEHUNG VOM {new_draw['date'].strftime('%Y-%m-%d')}")
report.append("-" * 70)
report.append(f"Hauptzahlen: {[new_draw[f'Z{i}'] for i in range(1, 6)]}")
report.append(f"Eurozahlen: [{new_draw['SZ1']}, {new_draw['SZ2']}]")
report.append("")
if evaluation:
report.append("EVALUATION DER TIPPS")
report.append("-" * 70)
report.append(f"Datei: {evaluation['file']}")
report.append(f"Tipps evaluiert: {len(evaluation['results'])}")
report.append(f"Avg Main Matches: {evaluation['avg_main_matches']:.2f}")
report.append(f"Avg Euro Matches: {evaluation['avg_euro_matches']:.2f}")
report.append(f"Bester Tipp: #{evaluation['best']['tip']}")
report.append(f" - Main Treffer: {evaluation['best']['main']}")
report.append(f" - Euro Treffer: {evaluation['best']['euro']}")
report.append("")
report.append("=" * 70)
# Speichern
with open(report_file, 'w') as f:
f.write('\n'.join(report))
# Ausgabe
for line in report:
print(line)
print(f"\n📁 Report gespeichert: {os.path.basename(report_file)}")
def run(self):
"""Führt kompletten Workflow aus."""
print()
print("=" * 70)
print("START: AUTOMATISCHER UPDATE & LEARNING WORKFLOW")
print("=" * 70)
# 1. Update Daten
print("\n[SCHRITT 1/4] Daten aktualisieren")
self.update_data()
# 2. Prüfe auf neue Ziehung
print("\n[SCHRITT 2/4] Neue Ziehung prüfen")
new_draw = self.check_for_new_draw()
if not new_draw:
print("\n⏭️ Keine neue Ziehung - Workflow beendet")
return True
# 3. Evaluiere Tipps
print("\n[SCHRITT 3/4] Tipps evaluieren")
evaluation = self.evaluate_tips(new_draw)
# 4. Learning Update
print("\n[SCHRITT 4/4] Learning Update")
self.perform_learning_update(new_draw)
# Report
self.generate_report(new_draw, evaluation)
# Log Update
log = self.load_learning_log()
log["updates"].append({
"timestamp": datetime.now().isoformat(),
"draw_date": new_draw['date'].strftime('%Y-%m-%d'),
"evaluation": evaluation.get('best', {}),
"avg_matches": {
'main': evaluation.get('avg_main_matches', 0),
'euro': evaluation.get('avg_euro_matches', 0)
}
})
self.save_learning_log(log)
# Sende Benachrichtigung
try:
best_match = {
'main_matches': evaluation.get('best', {}).get('main', 0),
'euro_matches': evaluation.get('best', {}).get('euro', 0)
}
evaluation_summary = {
'avg_main': evaluation.get('avg_main_matches', 0),
'avg_euro': evaluation.get('avg_euro_matches', 0)
}
self.notifier.send_draw_results(new_draw, evaluation_summary, best_match)
except Exception as e:
print(f"⚠️ Benachrichtigung fehlgeschlagen: {e}")
print("\n" + "=" * 70)
print("✅ WORKFLOW ERFOLGREICH ABGESCHLOSSEN")
print("=" * 70)
return True
def main():
"""Hauptfunktion."""
import argparse
parser = argparse.ArgumentParser(
description="Automatisches Update & Learning nach Ziehung"
)
parser.add_argument(
'--data-dir',
type=str,
default="/Users/sebastianfrohlich/Projekte/Eurojackpot/data",
help='Daten-Verzeichnis'
)
args = parser.parse_args()
# Run Workflow
workflow = AutoUpdateAndLearn(args.data_dir)
success = workflow.run()
sys.exit(0 if success else 1)
if __name__ == "__main__":
main()