import os import subprocess from datetime import datetime, timedelta from fastapi import FastAPI from apscheduler.schedulers.background import BackgroundScheduler import uvicorn app = FastAPI() scheduler = BackgroundScheduler() # Configuration from Environment Variables INTERVAL_HOURS = int(os.getenv("BUILD_INTERVAL", 6)) HF_TOKEN = os.getenv("HF_TOKEN", None) HOST_REPO = "lainlives/bldr" # State tracking status_info = { "last_run": None, "next_run": datetime.now(), "is_running": False } def run_builds(): """The core build logic.""" status_info["is_running"] = True print(f"[{datetime.now()}] Starting build sequence...") scripts = ["llama.py", "wheelmaker.py"] try: for script in scripts: # check=True will raise an error if the script fails subprocess.run(["python", script], check=True) except subprocess.CalledProcessError as e: print(f"Build failed at {script}: {e}") finally: status_info["last_run"] = datetime.now() status_info["next_run"] = datetime.now() + timedelta(hours=INTERVAL_HOURS) status_info["is_running"] = False print(f"[{datetime.now()}] Sequence finished. Next run: {status_info['next_run']}") @app.get("/") def get_status(): """Human-readable status and countdown.""" now = datetime.now() time_remaining = status_info["next_run"] - now return { "status": "Busy" if status_info["is_running"] else "Idle", "interval_configured": f"{INTERVAL_HOURS}h", "last_run": status_info["last_run"], "next_run": status_info["next_run"], "countdown": str(time_remaining).split(".")[0] if time_remaining.total_seconds() > 0 else "Pending..." } @app.post("/force") def force_build(): """Manually trigger the build sequence via API.""" if status_info["is_running"]: return {"message": "Build already in progress."}, 409 # This tells the scheduler to run the job 'build_job' immediately scheduler.get_job('build_job').modify(next_run_time=datetime.now()) return {"message": "Manual build triggered successfully."} @app.get("/next") def get_next_raw(): """Clean endpoint for programmatic access.""" return {"next_run_iso": status_info["next_run"].isoformat()} print(f"Starting {HOST_REPO}") if __name__ == "__main__": # Schedule the job and give it an ID so we can 'force' it later scheduler.add_job( run_builds, 'interval', hours=INTERVAL_HOURS, next_run_time=datetime.now(), id='build_job' ) scheduler.start() uvicorn.run(app, host="0.0.0.0", port=7860)