temp / instructor /api.py
CheeksTheGeek's picture
Initial commit: LLM Code Deployment System
c5292d8 unverified
"""Instructor API endpoint for receiving repo submissions."""
from datetime import datetime
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from instructor.database import Database
from shared.logger import setup_logger
from shared.models import RepoSubmission
logger = setup_logger(__name__)
app = FastAPI(
title="LLM Code Deployment - Instructor API",
description="API endpoint for receiving and validating repo submissions",
version="1.0.0",
)
# Initialize database
db = Database()
@app.on_event("startup")
async def startup_event():
"""Create database tables on startup."""
db.create_tables()
logger.info("Database initialized")
@app.post("/api/evaluate")
async def evaluate_submission(submission: RepoSubmission) -> JSONResponse:
"""Receive and validate repo submission.
Args:
submission: Repository submission from student
Returns:
HTTP 200 on success, HTTP 400 on validation failure
"""
logger.info(
f"Received submission: {submission.email}, "
f"task {submission.task}, round {submission.round}"
)
# Validate submission against task record
task = db.get_task_by_nonce(submission.nonce)
if not task:
logger.error(f"Invalid nonce: {submission.nonce}")
raise HTTPException(status_code=400, detail="Invalid nonce")
# Validate fields match
if task.email != submission.email:
logger.error(f"Email mismatch: expected {task.email}, got {submission.email}")
raise HTTPException(status_code=400, detail="Email mismatch")
if task.task != submission.task:
logger.error(f"Task mismatch: expected {task.task}, got {submission.task}")
raise HTTPException(status_code=400, detail="Task mismatch")
if task.round != submission.round:
logger.error(f"Round mismatch: expected {task.round}, got {submission.round}")
raise HTTPException(status_code=400, detail="Round mismatch")
# Check if already submitted
try:
existing = db.get_session().query(db.Repo).filter_by(nonce=submission.nonce).first()
if existing:
logger.warning(f"Duplicate submission for nonce {submission.nonce}")
return JSONResponse(
status_code=200,
content={
"status": "duplicate",
"message": "Submission already received",
},
)
finally:
db.get_session().close()
# Add to repos table
try:
repo = db.add_repo(
{
"timestamp": datetime.utcnow(),
"email": submission.email,
"task": submission.task,
"round": submission.round,
"nonce": submission.nonce,
"repo_url": submission.repo_url,
"commit_sha": submission.commit_sha,
"pages_url": submission.pages_url,
}
)
logger.info(
f"Added repo submission: {submission.task}, round {submission.round}, "
f"repo {submission.repo_url}"
)
return JSONResponse(
status_code=200,
content={
"status": "success",
"message": "Submission received and queued for evaluation",
"repo_id": repo.id,
},
)
except Exception as e:
logger.error(f"Failed to add repo submission: {e}", exc_info=True)
raise HTTPException(status_code=500, detail="Internal server error")
@app.get("/api/submissions/{email}")
async def get_submissions(email: str) -> JSONResponse:
"""Get all submissions for an email.
Args:
email: Student email
Returns:
List of submissions
"""
repos = db.get_repos(email=email)
return JSONResponse(content=[repo.to_dict() for repo in repos])
@app.get("/api/results/{email}")
async def get_results(email: str) -> JSONResponse:
"""Get all evaluation results for an email.
Args:
email: Student email
Returns:
List of evaluation results
"""
results = db.get_results(email=email)
return JSONResponse(content=[result.to_dict() for result in results])
@app.get("/health")
async def health_check() -> JSONResponse:
"""Health check endpoint.
Returns:
Health status
"""
return JSONResponse(
content={
"status": "healthy",
"timestamp": datetime.utcnow().isoformat(),
}
)
if __name__ == "__main__":
import uvicorn
from shared.config import settings
logger.info(f"Starting Instructor API on port {settings.instructor_api_port}")
uvicorn.run(
"instructor.api:app",
host="0.0.0.0",
port=settings.instructor_api_port,
reload=True,
)