Team Ai
Apppublic

24f3001764/llm_code_deployment

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
main.py282 linesDownload Raw Back to src
1import asyncio2import logging3import time4from datetime import datetime5from fastapi import FastAPI, HTTPException, BackgroundTasks6from fastapi.responses import JSONResponse7from src.models import TaskRequest, APIResponse, EvaluationPayload8from src.config import config9from src.utils import decode_and_save_attachments, sanitize_repo_name10from src.llm_generator import LLMAppGenerator11from src.github_manager import GitHubManager12from src.evaluator import EvaluationNotifier13 14# Configure logging15logging.basicConfig(16    level=logging.INFO,17    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'18)19logger = logging.getLogger(__name__)20 21# Initialize FastAPI22app = FastAPI(23    title="LLM Code Deployment API",24    description="Automated app generation and deployment system",25    version="1.0.0"26)27 28# Store task state (in production, use a database)29task_state = {}30 31 32@app.on_event("startup")33async def startup_event():34    """Validate configuration on startup"""35    try:36        config.validate()37        logger.info("Configuration validated successfully")38    except ValueError as e:39        logger.error(f"Configuration error: {e}")40        logger.error("Please set up your .env file based on .env.example")41 42 43@app.get("/")44async def root():45    """Health check endpoint"""46    return {47        "status": "running",48        "service": "LLM Code Deployment API",49        "version": "1.0.0"50    }51 52 53@app.post("/request", response_model=APIResponse)54async def handle_request(55    request: TaskRequest,56    background_tasks: BackgroundTasks57):58    """59    Main endpoint to receive task requests60    Validates secret, returns immediate 200, then processes in background61    """62    logger.info(f"Received request for task: {request.task}, round: {request.round}")63    64    # Verify secret65    if request.secret != config.STUDENT_SECRET:66        logger.warning(f"Invalid secret for task {request.task}")67        raise HTTPException(status_code=401, detail="Invalid secret")68    69    # Check if task is already being processed70    task_key = f"{request.task}-{request.round}"71    if task_key in task_state and task_state[task_key].get("status") == "processing":72        logger.warning(f"Task {task_key} is already being processed")73        return APIResponse(74            status="accepted",75            message="Task is already being processed",76            task=request.task,77            round=request.round78        )79    80    # Mark as processing81    task_state[task_key] = {82        "status": "processing",83        "started_at": datetime.now().isoformat()84    }85    86    # Schedule background processing87    if request.round == 1:88        background_tasks.add_task(process_build_task, request)89    else:90        background_tasks.add_task(process_revision_task, request)91    92    # Return immediate 200 response93    return APIResponse(94        status="accepted",95        message=f"Task {request.task} round {request.round} accepted for processing",96        task=request.task,97        round=request.round98    )99 100 101async def process_build_task(request: TaskRequest):102    """Process round 1: Build and deploy new app"""103    task_key = f"{request.task}-{request.round}"104    start_time = time.time()105    106    try:107        logger.info(f"Starting build task: {request.task}")108        109        # 1. Decode and save attachments110        attachments = await decode_and_save_attachments(request.attachments, request.task)111        logger.info(f"Saved {len(attachments)} attachments")112        113        # 2. Generate app using LLM114        generator = LLMAppGenerator()115        app_dir = await generator.generate_app(116            brief=request.brief,117            checks=request.checks,118            attachments=attachments,119            task_id=request.task120        )121        logger.info(f"Generated app at: {app_dir}")122        123        # 3. Create GitHub repo and deploy to Pages124        elapsed = time.time() - start_time125        if elapsed > config.EVALUATION_TIMEOUT - 60:  # Leave 1 min buffer126            logger.warning(f"Approaching timeout ({elapsed:.1f}s elapsed)")127        128        github_mgr = GitHubManager()129        repo_url, commit_sha, pages_url = await github_mgr.create_and_deploy(130            app_dir=app_dir,131            task_id=request.task132        )133        logger.info(f"Deployed to GitHub Pages: {pages_url}")134        135        # 4. Notify evaluation URL136        elapsed = time.time() - start_time137        logger.info(f"Task processing took {elapsed:.1f}s")138        139        if elapsed > config.EVALUATION_TIMEOUT:140            logger.error(f"Task exceeded timeout ({elapsed:.1f}s > {config.EVALUATION_TIMEOUT}s)")141            raise TimeoutError(f"Task processing exceeded {config.EVALUATION_TIMEOUT}s")142        143        notifier = EvaluationNotifier()144        payload = EvaluationPayload(145            email=request.email,146            task=request.task,147            round=request.round,148            nonce=request.nonce,149            repo_url=repo_url,150            commit_sha=commit_sha,151            pages_url=pages_url152        )153        154        success = await notifier.notify(request.evaluation_url, payload)155        156        # Update task state157        task_state[task_key] = {158            "status": "completed" if success else "failed",159            "completed_at": datetime.now().isoformat(),160            "repo_url": repo_url,161            "pages_url": pages_url,162            "notification_sent": success163        }164        165        logger.info(f"Build task completed: {request.task}")166    167    except Exception as e:168        logger.error(f"Build task failed: {e}", exc_info=True)169        task_state[task_key] = {170            "status": "failed",171            "error": str(e),172            "failed_at": datetime.now().isoformat()173        }174 175 176async def process_revision_task(request: TaskRequest):177    """Process round 2: Update existing app"""178    task_key = f"{request.task}-{request.round}"179    start_time = time.time()180    181    try:182        logger.info(f"Starting revision task: {request.task}")183        184        # Get repo name from round 1185        round1_key = f"{request.task}-1"186        if round1_key not in task_state:187            raise ValueError("Round 1 must be completed before round 2")188        189        repo_name = sanitize_repo_name(request.task)190        191        # 1. Decode and save attachments192        attachments = await decode_and_save_attachments(request.attachments, request.task)193        logger.info(f"Saved {len(attachments)} attachments")194        195        # 2. Generate updated app using LLM196        generator = LLMAppGenerator()197        app_dir = await generator.generate_app(198            brief=request.brief,199            checks=request.checks,200            attachments=attachments,201            task_id=request.task202        )203        logger.info(f"Generated updated app at: {app_dir}")204        205        # 3. Update GitHub repo206        elapsed = time.time() - start_time207        if elapsed > config.EVALUATION_TIMEOUT - 60:  # Leave 1 min buffer208            logger.warning(f"Approaching timeout ({elapsed:.1f}s elapsed)")209        210        github_mgr = GitHubManager()211        commit_sha, pages_url = await github_mgr.update_repo(212            repo_name=repo_name,213            app_dir=app_dir,214            update_message=f"Round {request.round} update"215        )216        logger.info(f"Updated GitHub Pages: {pages_url}")217        218        # 4. Notify evaluation URL219        elapsed = time.time() - start_time220        logger.info(f"Task processing took {elapsed:.1f}s")221        222        if elapsed > config.EVALUATION_TIMEOUT:223            logger.error(f"Task exceeded timeout ({elapsed:.1f}s > {config.EVALUATION_TIMEOUT}s)")224            raise TimeoutError(f"Task processing exceeded {config.EVALUATION_TIMEOUT}s")225        226        notifier = EvaluationNotifier()227        repo_url = f"https://github.com/{config.GITHUB_USERNAME}/{repo_name}"228        payload = EvaluationPayload(229            email=request.email,230            task=request.task,231            round=request.round,232            nonce=request.nonce,233            repo_url=repo_url,234            commit_sha=commit_sha,235            pages_url=pages_url236        )237        238        success = await notifier.notify(request.evaluation_url, payload)239        240        # Update task state241        task_state[task_key] = {242            "status": "completed" if success else "failed",243            "completed_at": datetime.now().isoformat(),244            "repo_url": repo_url,245            "pages_url": pages_url,246            "notification_sent": success247        }248        249        logger.info(f"Revision task completed: {request.task}")250    251    except Exception as e:252        logger.error(f"Revision task failed: {e}", exc_info=True)253        task_state[task_key] = {254            "status": "failed",255            "error": str(e),256            "failed_at": datetime.now().isoformat()257        }258 259 260@app.get("/status/{task_id}")261async def get_status(task_id: str):262    """Get status of a task"""263    results = {}264    for key, state in task_state.items():265        if key.startswith(task_id):266            results[key] = state267    268    if not results:269        raise HTTPException(status_code=404, detail="Task not found")270    271    return results272 273 274if __name__ == "__main__":275    import uvicorn276    uvicorn.run(277        "src.main:app",278        host=config.API_HOST,279        port=config.API_PORT,280        reload=True281    )282