| 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) |