2025-12-16 14:47:59 +01:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
"""
|
|
|
|
|
|
Automatischer Lotto 6aus49 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 * * 3,0 cd /path/to/Lotto && 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 LottoAPIUpdater
|
|
|
|
|
|
from scripts.generators.ultimate_ai_ml_hybrid_generator import UltimateAIMLHybridGenerator
|
|
|
|
|
|
from scripts.utils.notifier import LottoNotifier
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AutoUpdateAndLearn:
|
|
|
|
|
|
"""Automatisches Update und Learning System."""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, data_dir: str):
|
|
|
|
|
|
self.data_dir = data_dir
|
|
|
|
|
|
# CSV file is in Lotto/data folder
|
|
|
|
|
|
# data_dir = .../Lotto/data
|
|
|
|
|
|
# We need .../Lotto/data/AlleLottozahlen.csv
|
|
|
|
|
|
self.data_file = os.path.join(data_dir, "AlleLottozahlen.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 = LottoNotifier()
|
|
|
|
|
|
|
|
|
|
|
|
print("🤖 AUTOMATISCHES UPDATE & LEARNING SYSTEM - LOTTO 6AUS49")
|
|
|
|
|
|
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
|
|
|
|
|
|
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']),
|
|
|
|
|
|
'Z6': int(latest_draw['Z6']),
|
|
|
|
|
|
'SZ': int(latest_draw['SZ']) if pd.notna(latest_draw['SZ']) else None
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = LottoAPIUpdater(self.data_file)
|
|
|
|
|
|
success = updater.update(api_name='github', 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)
|
|
|
|
|
|
|
2026-01-07 09:20:49 +01:00
|
|
|
|
# Finde Tipps-Datei die VOR der Ziehung generiert wurde
|
2025-12-16 14:47:59 +01:00
|
|
|
|
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 {}
|
|
|
|
|
|
|
2026-01-07 09:20:49 +01:00
|
|
|
|
# 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_lotto_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}")
|
2025-12-16 14:47:59 +01:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
tips_df = pd.read_csv(latest_tips_file)
|
|
|
|
|
|
|
|
|
|
|
|
# Extrahiere gezogene Zahlen
|
|
|
|
|
|
drawn_main = [new_draw[f'Z{i}'] for i in range(1, 7)]
|
|
|
|
|
|
drawn_sz = new_draw.get('SZ')
|
|
|
|
|
|
|
|
|
|
|
|
print(f" 🎲 Gezogene Zahlen: {drawn_main} + SZ: {drawn_sz}")
|
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
|
|
results = []
|
|
|
|
|
|
best_matches = {'main': 0, 'sz': False, 'tip': None}
|
|
|
|
|
|
|
|
|
|
|
|
for _, tip in tips_df.iterrows():
|
|
|
|
|
|
# Parse Hauptzahlen (Column name is 'Numbers' in Lotto)
|
|
|
|
|
|
main_str = tip['Numbers'] if 'Numbers' in tip else tip.get('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 Superzahl
|
|
|
|
|
|
tip_sz = int(tip['Superzahl'])
|
|
|
|
|
|
|
|
|
|
|
|
# Zähle Treffer
|
|
|
|
|
|
main_matches = len(set(tip_main) & set(drawn_main))
|
|
|
|
|
|
sz_match = (tip_sz == drawn_sz) if drawn_sz is not None else False
|
|
|
|
|
|
|
|
|
|
|
|
results.append({
|
|
|
|
|
|
'tip_number': tip['Tip_Number'],
|
|
|
|
|
|
'strategy': tip['Strategy'],
|
|
|
|
|
|
'main_matches': main_matches,
|
|
|
|
|
|
'sz_match': sz_match,
|
|
|
|
|
|
'total_score': main_matches + (1 if sz_match else 0)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
# Track best
|
|
|
|
|
|
total_score = main_matches + (1 if sz_match else 0)
|
|
|
|
|
|
best_total = best_matches['main'] + (1 if best_matches['sz'] else 0)
|
|
|
|
|
|
|
|
|
|
|
|
if total_score > best_total:
|
|
|
|
|
|
best_matches = {
|
|
|
|
|
|
'main': main_matches,
|
|
|
|
|
|
'sz': sz_match,
|
|
|
|
|
|
'tip': tip['Tip_Number']
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Ausgabe
|
|
|
|
|
|
print(f" {'Tip':<5} {'Strategie':<15} {'Main':<6} {'SZ':<5} {'Score':<7} {'Bewertung'}")
|
|
|
|
|
|
print(" " + "-" * 60)
|
|
|
|
|
|
|
|
|
|
|
|
for r in results:
|
|
|
|
|
|
rating = self._get_match_rating(r['main_matches'], r['sz_match'])
|
|
|
|
|
|
sz_indicator = "✅" if r['sz_match'] else "⚪"
|
|
|
|
|
|
print(f" #{r['tip_number']:<4} {r['strategy']:<15} "
|
|
|
|
|
|
f"{r['main_matches']:<6} {sz_indicator:<5} "
|
|
|
|
|
|
f"{r['total_score']:<7} {rating}")
|
|
|
|
|
|
|
|
|
|
|
|
print()
|
|
|
|
|
|
print(f" 🏆 Bester Tipp: #{best_matches['tip']} "
|
|
|
|
|
|
f"({best_matches['main']} Main" +
|
|
|
|
|
|
(f" + SZ" if best_matches['sz'] else "") + ")")
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
'file': tip_files[0],
|
|
|
|
|
|
'results': results,
|
|
|
|
|
|
'best': best_matches,
|
|
|
|
|
|
'avg_main_matches': sum(r['main_matches'] for r in results) / len(results),
|
|
|
|
|
|
'sz_match_rate': sum(1 for r in results if r['sz_match']) / 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, sz_match: bool) -> str:
|
|
|
|
|
|
"""Bewertung der Treffer."""
|
|
|
|
|
|
if main == 6 and sz_match:
|
|
|
|
|
|
return "🏆 JACKPOT!"
|
|
|
|
|
|
elif main == 6:
|
|
|
|
|
|
return "💰 Klasse 2"
|
|
|
|
|
|
elif main == 5 and sz_match:
|
|
|
|
|
|
return "💰 Klasse 3"
|
|
|
|
|
|
elif main == 5:
|
|
|
|
|
|
return "💰 Klasse 4"
|
|
|
|
|
|
elif main == 4 and sz_match:
|
|
|
|
|
|
return "💵 Klasse 5"
|
|
|
|
|
|
elif main == 4:
|
|
|
|
|
|
return "💵 Klasse 6"
|
|
|
|
|
|
elif main == 3 and sz_match:
|
|
|
|
|
|
return "✅ Klasse 7"
|
|
|
|
|
|
elif main == 3:
|
|
|
|
|
|
return "✅ Klasse 8"
|
|
|
|
|
|
elif main == 2 and sz_match:
|
|
|
|
|
|
return "👍 Klasse 9"
|
|
|
|
|
|
elif main >= 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 = UltimateAIMLHybridGenerator(
|
|
|
|
|
|
self.data_file,
|
|
|
|
|
|
fast_mode=True
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# Learning Update (falls vorhanden)
|
|
|
|
|
|
if hasattr(generator, 'real_time_learner'):
|
|
|
|
|
|
generator.real_time_learner.learn_from_result(new_draw)
|
|
|
|
|
|
print(" ✅ Learning Update durchgeführt")
|
|
|
|
|
|
|
|
|
|
|
|
# Performance Tracking (falls vorhanden)
|
|
|
|
|
|
if hasattr(generator, 'performance_tracker'):
|
|
|
|
|
|
generator.performance_tracker.evaluate_predictions(new_draw)
|
|
|
|
|
|
print(" 📊 Performance getrackt")
|
|
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
print(f" ⚠️ Learning Update nicht verfügbar: {e}")
|
|
|
|
|
|
print(" ℹ️ Generator funktioniert weiterhin normal")
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
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("LOTTO 6AUS49 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, 7)]}")
|
|
|
|
|
|
report.append(f"Superzahl: {new_draw.get('SZ', 'N/A')}")
|
|
|
|
|
|
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"SZ Match Rate: {evaluation['sz_match_rate']*100:.1f}%")
|
|
|
|
|
|
report.append(f"Bester Tipp: #{evaluation['best']['tip']}")
|
|
|
|
|
|
report.append(f" - Main Treffer: {evaluation['best']['main']}")
|
|
|
|
|
|
report.append(f" - SZ Match: {'Ja' if evaluation['best']['sz'] else 'Nein'}")
|
|
|
|
|
|
|
|
|
|
|
|
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),
|
|
|
|
|
|
'sz_rate': evaluation.get('sz_match_rate', 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
self.save_learning_log(log)
|
|
|
|
|
|
|
|
|
|
|
|
# Sende Benachrichtigung
|
|
|
|
|
|
try:
|
|
|
|
|
|
best_match = {
|
|
|
|
|
|
'main_matches': evaluation.get('best', {}).get('main', 0),
|
|
|
|
|
|
'sz_match': evaluation.get('best', {}).get('sz', False)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
evaluation_summary = {
|
|
|
|
|
|
'avg_main': evaluation.get('avg_main_matches', 0),
|
|
|
|
|
|
'sz_rate': evaluation.get('sz_match_rate', 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,
|
2026-01-14 11:56:15 +01:00
|
|
|
|
default="/Users/sebastianfrohlich/Projekte/Lotto/data",
|
2025-12-16 14:47:59 +01:00
|
|
|
|
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()
|