| | 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() |
| |
|
| | |
| | INTERVAL_HOURS = int(os.getenv("BUILD_INTERVAL", 6)) |
| | HF_TOKEN = os.getenv("HF_TOKEN", None) |
| | HOST_REPO = "lainlives/bldr" |
| |
|
| | |
| | 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: |
| | |
| | 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 |
| |
|
| | |
| | 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__": |
| | |
| | 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) |