kshitijp3030/tiercode-executor
0
1from fastapi import FastAPI, BackgroundTasks, HTTPException2from fastapi.responses import FileResponse3from pydantic import BaseModel4from typing import Dict5import os6import uuid7import shutil8import mimetypes9import subprocess10 11app = FastAPI(title="TierCode Executor")12 13jobs = {}14 15BASE = "/tmp/jobs"16os.makedirs(BASE, exist_ok=True)17 18 19# --------------------------------------------------------20# Request21# --------------------------------------------------------22 23class ExecuteRequest(BaseModel):24 prompt: str25 entry: str26 run: str27 files: Dict[str, str] = {}28 29 30# --------------------------------------------------------31# Home32# --------------------------------------------------------33 34@app.get("/")35def home():36 return {"message": "TierCode Executor Running"}37 38 39@app.get("/health")40def health():41 return {"status": "ok"}42 43 44# --------------------------------------------------------45# Worker46# --------------------------------------------------------47 48def worker(job_id):49 50 job = jobs[job_id]51 52 job["status"] = "running"53 54 workspace = job["workspace"]55 56 try:57 58 # -----------------------------59 # Write files60 # -----------------------------61 62 for filename, content in job["files"].items():63 64 filepath = os.path.join(workspace, filename)65 66 os.makedirs(os.path.dirname(filepath), exist_ok=True)67 68 with open(filepath, "w", encoding="utf-8") as f:69 f.write(content)70 71 job.pop("files", None)72 73 entry = job["entry"]74 run = job["run"].strip()75 76 # -----------------------------77 # Static website78 # -----------------------------79 80 if entry.endswith(".html"):81 82 job["status"] = "completed"83 return84 85 # -----------------------------86 # Execute command87 # -----------------------------88 89 result = subprocess.run(90 run.split(),91 cwd=workspace,92 capture_output=True,93 text=True,94 timeout=6095 )96 97 job["stdout"] = result.stdout98 job["stderr"] = result.stderr99 100 if result.returncode == 0:101 job["status"] = "completed"102 else:103 job["status"] = "failed"104 105 except subprocess.TimeoutExpired:106 107 job["status"] = "failed"108 job["stderr"] = "Execution timed out."109 110 except Exception as e:111 112 job["status"] = "failed"113 job["stderr"] = str(e)114 115 116# --------------------------------------------------------117# Execute118# --------------------------------------------------------119 120@app.post("/execute")121def execute(request: ExecuteRequest,122 background_tasks: BackgroundTasks):123 124 job_id = str(uuid.uuid4())125 126 workspace = os.path.join(BASE, job_id)127 128 os.makedirs(workspace, exist_ok=True)129 130 jobs[job_id] = {131 "status": "queued",132 "prompt": request.prompt,133 "entry": request.entry,134 "run": request.run,135 "workspace": workspace,136 "files": request.files137 }138 139 background_tasks.add_task(worker, job_id)140 141 return {142 "status": "queued",143 "job_id": job_id144 }145 146 147# --------------------------------------------------------148# Status149# --------------------------------------------------------150 151@app.get("/status/{job_id}")152def status(job_id: str):153 154 if job_id not in jobs:155 raise HTTPException(404, "Job not found")156 157 job = jobs[job_id]158 159 return {160 161 "job_id": job_id,162 163 "status": job["status"],164 165 "prompt": job["prompt"],166 167 "entry": job["entry"],168 169 "run": job["run"],170 171 "stdout": job.get("stdout", ""),172 173 "stderr": job.get("stderr", ""),174 175 "preview_url": f"/preview/{job_id}/{job['entry']}",176 177 "files_url": f"/files/{job_id}",178 179 "download_url": f"/download/{job_id}"180 181 }182 183 184# --------------------------------------------------------185# Files186# --------------------------------------------------------187 188@app.get("/files/{job_id}")189def files(job_id: str):190 191 if job_id not in jobs:192 raise HTTPException(404, "Job not found")193 194 workspace = jobs[job_id]["workspace"]195 196 file_list = []197 198 for root, dirs, files in os.walk(workspace):199 200 for file in files:201 202 full = os.path.join(root, file)203 204 relative = os.path.relpath(full, workspace)205 206 file_list.append(relative)207 208 return {209 210 "job_id": job_id,211 212 "count": len(file_list),213 214 "files": sorted(file_list)215 216 }217 218 219# --------------------------------------------------------220# Preview221# --------------------------------------------------------222 223@app.get("/preview/{job_id}")224@app.get("/preview/{job_id}/{file_path:path}")225def preview(job_id: str, file_path: str = ""):226 227 if job_id not in jobs:228 raise HTTPException(404, "Job not found")229 230 workspace = os.path.abspath(jobs[job_id]["workspace"])231 232 if file_path == "":233 file_path = jobs[job_id]["entry"]234 235 full_path = os.path.abspath(236 os.path.join(workspace, file_path)237 )238 239 if not full_path.startswith(workspace):240 raise HTTPException(403, "Forbidden")241 242 if not os.path.exists(full_path):243 raise HTTPException(404, "File not found")244 245 media = mimetypes.guess_type(full_path)[0]246 247 return FileResponse(248 full_path,249 media_type=media250 )251 252 253# --------------------------------------------------------254# Download255# --------------------------------------------------------256 257@app.get("/download/{job_id}")258def download(job_id: str):259 260 if job_id not in jobs:261 raise HTTPException(404, "Job not found")262 263 workspace = jobs[job_id]["workspace"]264 265 zip_path = workspace + ".zip"266 267 if os.path.exists(zip_path):268 os.remove(zip_path)269 270 shutil.make_archive(271 workspace,272 "zip",273 workspace274 )275 276 return FileResponse(277 zip_path,278 filename=f"{job_id}.zip",279 media_type="application/zip"280 )281 282 283# --------------------------------------------------------284 285if __name__ == "__main__":286 287 import uvicorn288 289 uvicorn.run(290 app,291 host="0.0.0.0",292 port=7860293 )294 