CoolFace
Apppublic

hiropr/llm-code-deployment

sourceHugging Facemitupdated 11mo agoView on Hugging Face
0likes
main.py178 linesDownload Raw Back to root
1from dotenv import load_dotenv2load_dotenv()3 4from fastapi import FastAPI, BackgroundTasks, HTTPException5from pydantic import BaseModel6import os, sqlite3, time, requests7from helpers import hash_secret8from github_utils import create_and_push_repo9from llm_utils import generate_files_from_brief10 11# === CONFIG ===12STORED_SECRET_HASH = os.environ.get("STORED_SECRET_HASH")13OWNER_GITHUB = os.environ.get("GITHUB_USER")14DB_PATH = os.environ.get("DB_PATH", "./tasks.db")15 16# Ensure DB writable (Hugging Face-safe)17try:18    os.makedirs(os.path.dirname(DB_PATH) or ".", exist_ok=True)19    with open(os.path.join(os.path.dirname(DB_PATH) or ".", ".db_write_test"), "w") as f:20        f.write("")21except (OSError, IOError):22    DB_PATH = "/tmp/tasks.db"23    os.makedirs("/tmp", exist_ok=True)24 25app = FastAPI(title="IITM LLM Code Deployment API")26 27def init_db():28    conn = sqlite3.connect(DB_PATH)29    cur = conn.cursor()30    cur.execute("""31        CREATE TABLE IF NOT EXISTS tasks (32            id INTEGER PRIMARY KEY,33            email TEXT,34            task TEXT,35            round INTEGER,36            nonce TEXT,37            secret_hash TEXT,38            brief TEXT,39            evaluation_url TEXT,40            status TEXT,41            created_at DATETIME DEFAULT CURRENT_TIMESTAMP42        )43    """)44    conn.commit()45    conn.close()46init_db()47 48 49class TaskRequest(BaseModel):50    email: str51    secret: str52    task: str53    round: int54    nonce: str55    brief: str = ""56    checks: list = []57    evaluation_url: str = None58    attachments: list = []59 60 61@app.post("/api-endpoint")62async def receive_task(req: TaskRequest, background_tasks: BackgroundTasks):63    if not STORED_SECRET_HASH:64        raise HTTPException(status_code=500, detail="Server secret not configured")65    if hash_secret(req.secret) != STORED_SECRET_HASH:66        raise HTTPException(status_code=403, detail="Invalid secret")67 68    conn = sqlite3.connect(DB_PATH)69    cur = conn.cursor()70    cur.execute(71        "INSERT INTO tasks (email, task, round, nonce, secret_hash, brief, evaluation_url, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",72        (req.email, req.task, req.round, req.nonce, STORED_SECRET_HASH, req.brief, req.evaluation_url, "received"),73    )74    conn.commit()75    conn.close()76 77    background_tasks.add_task(process_task, req.dict())78    return {"status": "accepted", "task": req.task, "round": req.round, "nonce": req.nonce}79 80 81def process_task(data: dict):82    task = data["task"]83    nonce = data["nonce"]84    round_number = data.get("round", 1)85    short = nonce.replace("-", "")[:8]86    repo_name = f"{task}-{short}"87 88    print(f"Processing {task} (Round {round_number})")89 90    try:91        files = generate_files_from_brief(92            brief=data["brief"],93            attachments=data.get("attachments", []),94            round_number=round_number,95            user=OWNER_GITHUB,96            repo_name=repo_name,97        )98        files["LICENSE"] = get_mit_license_text()99 100        repo_url, commit_sha, pages_url = create_and_push_repo(101            repo_name, files,102            evaluation_data={103                "email": data["email"],104                "task": task,105                "round": round_number,106                "nonce": nonce,107                "evaluation_url": data.get("evaluation_url"),108            },109        )110 111        post_to_evaluation_url(data, repo_url, commit_sha, pages_url)112 113        conn = sqlite3.connect(DB_PATH)114        cur = conn.cursor()115        cur.execute(116            "UPDATE tasks SET status=? WHERE nonce=?",117            (f"completed: {task} round {round_number}", nonce),118        )119        conn.commit()120        conn.close()121        print(f"โœ… Task {task} (round {round_number}) completed successfully")122        print(f"๐Ÿ”— Pages URL: {pages_url}")123 124    except Exception as e:125        print(f"โŒ Process failed for {task} (round {round_number}): {e}")126        conn = sqlite3.connect(DB_PATH)127        cur = conn.cursor()128        cur.execute("UPDATE tasks SET status=? WHERE nonce=?", (f"failed: {str(e)}", nonce))129        conn.commit()130        conn.close()131 132 133def post_to_evaluation_url(data, repo_url, commit_sha, pages_url):134    """POST to evaluation_url with exponential backoff (per IITM spec)."""135    if not data.get("evaluation_url"):136        print("โš ๏ธ No evaluation_url provided, skipping callback.")137        return138 139    payload = {140        "email": data["email"],141        "task": data["task"],142        "round": data["round"],143        "nonce": data["nonce"],144        "repo_url": repo_url,145        "commit_sha": commit_sha,146        "pages_url": pages_url,147    }148 149    for delay in [1, 2, 4, 8]:150        try:151            res = requests.post(data["evaluation_url"], json=payload, timeout=10)152            print(f"๐Ÿ“จ Evaluation POST โ†’ {res.status_code}")153            if res.status_code == 200:154                print("โœ… Evaluation server acknowledged successfully.")155                return156        except Exception as e:157            print(f"โš ๏ธ Evaluation POST failed (retrying in {delay}s): {e}")158        time.sleep(delay)159    print("โŒ Could not reach evaluation_url after multiple retries.")160 161 162def get_mit_license_text():163    return """MIT License164 165Copyright (c) 2025166 167Permission is hereby granted, free of charge, to any person obtaining a copy168of this software and associated documentation files (the "Software"), to deal169in the Software without restriction, including without limitation the rights170to use, copy, modify, merge, publish, distribute, sublicense, and/or sell171copies of the Software, and to permit persons to whom the Software is172furnished to do so, subject to the following conditions:173 174THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR175IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,176FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.177"""178