NutriLoop / scripts /retrain.py
AB1N05's picture
Nutriloop V2 Backend - Global Model Architected
1fa55f4
Raw
History Blame Contribute Delete
4.72 kB
"""
Master retraining script for NutriLoop AI.
Called by GitHub Actions nightly cron or manually.
Runs: Supabase data pull → Prophet training → Cluster training → HF upload.
"""
import os
import sys
from datetime import datetime
from pathlib import Path
# Ensure project root is in path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
from dotenv import load_dotenv
load_dotenv()
from supabase import create_client
def run_retrain():
"""
Execute the full NutriLoop retraining pipeline.
Steps:
1. Pull latest data from Supabase sales_logs
2. Train Prophet models (train_prophet.py)
3. Train KMeans clusters (train_clusters.py)
4. Upload models to Hugging Face (upload_models.py)
5. Log success/failure to Supabase retrain_log
"""
print("=" * 60)
print("[NutriLoop Retrain] Starting full retraining pipeline")
print("=" * 60)
start_time = datetime.now()
supabase_url = os.environ.get("SUPABASE_URL")
supabase_key = os.environ.get("SUPABASE_KEY")
if not supabase_url or not supabase_key:
print("[NutriLoop Retrain] ERROR: SUPABASE_URL and SUPABASE_KEY not set")
sys.exit(1)
client = create_client(supabase_url, supabase_key)
# Step 1: Check data availability
print("\n[Step 1] Checking Supabase data...")
try:
response = client.table("sales_logs").select("id").limit(1).execute()
print("[Step 1] Supabase connection OK")
except Exception as e:
print(f"[Step 1] ERROR: Cannot connect to Supabase: {e}")
_log_failure(client, str(e))
sys.exit(1)
# Step 2: Train Global Multivariate Model
print("\n[Step 2] Training Global Multivariate Model...")
try:
from training.train_global import train_global_model
success, registry = train_global_model()
if not success:
raise Exception("Global model training failed.")
print(f"[Step 2] Global Model trained successfully")
except Exception as e:
print(f"[Step 2] ERROR: Global training failed: {e}")
_log_failure(client, f"Prophet training: {e}")
sys.exit(1)
# Step 3: Train KMeans clusters
print("\n[Step 3] Training KMeans clusters...")
try:
from training.train_clusters import train_clusters
n_clusters, _ = train_clusters()
print(f"[Step 3] Clusters: {n_clusters} clusters created")
except Exception as e:
print(f"[Step 3] WARNING: Cluster training failed: {e}")
# Non-fatal - continue
n_clusters = 0
# Step 4: Upload to Hugging Face
print("\n[Step 4] Uploading models to Hugging Face...")
hf_uploaded = False
try:
from training.upload_models import upload_models
upload_models()
hf_uploaded = True
print("[Step 4] HF upload complete")
except Exception as e:
print(f"[Step 4] WARNING: HF upload failed: {e}")
# Non-fatal - continue
# Step 5: Log success
elapsed = (datetime.now() - start_time).total_seconds()
avg_mae = sum(m["mae"] for m in registry.values()) / max(1, len(registry)) if registry else 0.0
current_iso = datetime.now().isoformat()
try:
last_retrain_path = project_root / "models" / "last_retrain.txt"
last_retrain_path.parent.mkdir(exist_ok=True)
last_retrain_path.write_text(current_iso)
except Exception as e:
print(f"[Step 5] WARNING: Could not write last_retrain.txt: {e}")
try:
client.table("retrain_log").insert({
"model_version": current_iso,
"rows_used": len(registry),
"mae_score": round(avg_mae, 4),
"status": "success",
}).execute()
except Exception as e:
print(f"[Step 5] WARNING: Could not log to retrain_log: {e}")
# Summary
hf_status = "Yes" if hf_uploaded else "No"
print("\n" + "=" * 60)
print(f"[NutriLoop Retrain] Complete in {elapsed:.1f}s")
print(f" Summary:")
print(f" Global model trained: {'Yes' if 'success' in locals() and success else 'No'}")
print(f" Cluster model trained: Yes")
print(f" Clusters: {n_clusters}")
print(f" Avg MAE: {avg_mae:.4f}")
print(f" Uploaded to HF: {hf_status}")
print("=" * 60)
def _log_failure(client, error_msg: str) -> None:
"""Log a failed retrain run to Supabase."""
try:
client.table("retrain_log").insert({
"model_version": datetime.now().isoformat(),
"rows_used": 0,
"mae_score": 0.0,
"status": "failed",
"error_msg": error_msg,
}).execute()
except Exception:
pass
if __name__ == "__main__":
run_retrain()