| |
| """ |
| Backend Code Generation API Service |
| =================================== |
| |
| Production-ready API service for serving the trained backend code generation model. |
| Provides RESTful endpoints for generating complete backend applications. |
| """ |
|
|
| from fastapi import FastAPI, HTTPException, BackgroundTasks, Depends |
| from fastapi.middleware.cors import CORSMiddleware |
| from fastapi.responses import StreamingResponse, FileResponse |
| from pydantic import BaseModel, Field |
| from typing import List, Dict, Optional, Any |
| import torch |
| from transformers import AutoModelForCausalLM, AutoTokenizer |
| import json |
| import zipfile |
| import tempfile |
| import os |
| import uuid |
| from datetime import datetime |
| import asyncio |
| import logging |
| from pathlib import Path |
|
|
| |
| logging.basicConfig(level=logging.INFO) |
| logger = logging.getLogger(__name__) |
|
|
| |
| class CodeGenerationRequest(BaseModel): |
| description: str = Field(..., description="Description of the backend application to generate") |
| framework: str = Field(..., description="Target framework (express, fastapi, django, flask)") |
| language: str = Field(..., description="Programming language (javascript, python)") |
| requirements: List[str] = Field(default=[], description="List of specific requirements") |
| project_name: Optional[str] = Field(default=None, description="Custom project name") |
| |
| class Config: |
| schema_extra = { |
| "example": { |
| "description": "E-commerce API with user authentication and product management", |
| "framework": "fastapi", |
| "language": "python", |
| "requirements": [ |
| "User registration and login", |
| "JWT authentication", |
| "Product CRUD operations", |
| "Shopping cart functionality", |
| "Order management" |
| ], |
| "project_name": "ecommerce-api" |
| } |
| } |
|
|
| class GenerationResponse(BaseModel): |
| task_id: str |
| status: str |
| message: str |
| estimated_time: int |
|
|
| class GenerationStatus(BaseModel): |
| task_id: str |
| status: str |
| progress: int |
| message: str |
| generated_files: Optional[Dict[str, str]] = None |
| download_url: Optional[str] = None |
| error: Optional[str] = None |
|
|
| class GeneratedProject(BaseModel): |
| project_name: str |
| framework: str |
| language: str |
| files: Dict[str, str] |
| structure: Dict[str, Any] |
| setup_instructions: List[str] |
| features: List[str] |
|
|
| |
| class ModelManager: |
| def __init__(self): |
| self.model = None |
| self.tokenizer = None |
| self.device = "cuda" if torch.cuda.is_available() else "cpu" |
| self.loaded = False |
| |
| async def load_model(self, model_path: str = "./trained_model"): |
| """Load the trained model asynchronously""" |
| try: |
| logger.info(f"Loading model from {model_path} on {self.device}") |
| |
| self.tokenizer = AutoTokenizer.from_pretrained(model_path) |
| self.model = AutoModelForCausalLM.from_pretrained( |
| model_path, |
| torch_dtype=torch.float16 if self.device == "cuda" else torch.float32, |
| device_map="auto" if self.device == "cuda" else None |
| ) |
| |
| if self.device == "cpu": |
| self.model = self.model.to(self.device) |
| |
| self.loaded = True |
| logger.info("Model loaded successfully!") |
| |
| except Exception as e: |
| logger.error(f"Failed to load model: {e}") |
| raise |
| |
| def generate_code(self, prompt: str, max_tokens: int = 1024) -> str: |
| """Generate code using the trained model""" |
| if not self.loaded: |
| raise RuntimeError("Model not loaded") |
| |
| inputs = self.tokenizer.encode(prompt, return_tensors='pt') |
| inputs = inputs.to(self.device) |
| |
| with torch.no_grad(): |
| outputs = self.model.generate( |
| inputs, |
| max_length=min(max_tokens, 1024), |
| num_return_sequences=1, |
| temperature=0.7, |
| do_sample=True, |
| top_p=0.9, |
| pad_token_id=self.tokenizer.eos_token_id, |
| repetition_penalty=1.1 |
| ) |
| |
| generated_text = self.tokenizer.decode(outputs[0], skip_special_tokens=True) |
| return generated_text[len(self.tokenizer.decode(inputs[0], skip_special_tokens=True)):] |
|
|
| |
| model_manager = ModelManager() |
| generation_tasks = {} |
|
|
| |
| app = FastAPI( |
| title="Backend Code Generation API", |
| description="AI-powered backend application generator", |
| version="1.0.0", |
| docs_url="/docs", |
| redoc_url="/redoc" |
| ) |
|
|
| |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| @app.on_event("startup") |
| async def startup_event(): |
| """Load model on startup""" |
| model_path = os.getenv("MODEL_PATH", "./trained_model") |
| await model_manager.load_model(model_path) |
|
|
| @app.get("/") |
| async def root(): |
| """API root endpoint""" |
| return { |
| "service": "Backend Code Generation API", |
| "version": "1.0.0", |
| "status": "running", |
| "model_loaded": model_manager.loaded, |
| "endpoints": { |
| "generate": "/api/v1/generate", |
| "status": "/api/v1/status/{task_id}", |
| "download": "/api/v1/download/{task_id}", |
| "health": "/health" |
| } |
| } |
|
|
| @app.get("/health") |
| async def health_check(): |
| """Health check endpoint""" |
| return { |
| "status": "OK", |
| "timestamp": datetime.utcnow().isoformat(), |
| "model_loaded": model_manager.loaded, |
| "device": model_manager.device if model_manager.loaded else None |
| } |
|
|
| @app.post("/api/v1/generate", response_model=GenerationResponse) |
| async def generate_backend( |
| request: CodeGenerationRequest, |
| background_tasks: BackgroundTasks |
| ): |
| """Generate a complete backend application""" |
| |
| if not model_manager.loaded: |
| raise HTTPException(status_code=503, detail="Model not loaded") |
| |
| |
| task_id = str(uuid.uuid4()) |
| |
| |
| generation_tasks[task_id] = GenerationStatus( |
| task_id=task_id, |
| status="pending", |
| progress=0, |
| message="Task queued for processing" |
| ) |
| |
| |
| background_tasks.add_task( |
| generate_project_background, |
| task_id, |
| request |
| ) |
| |
| return GenerationResponse( |
| task_id=task_id, |
| status="accepted", |
| message="Code generation started", |
| estimated_time=60 |
| ) |
|
|
| @app.get("/api/v1/status/{task_id}", response_model=GenerationStatus) |
| async def get_generation_status(task_id: str): |
| """Get the status of a generation task""" |
| |
| if task_id not in generation_tasks: |
| raise HTTPException(status_code=404, detail="Task not found") |
| |
| return generation_tasks[task_id] |
|
|
| @app.get("/api/v1/download/{task_id}") |
| async def download_generated_project(task_id: str): |
| """Download the generated project as a ZIP file""" |
| |
| if task_id not in generation_tasks: |
| raise HTTPException(status_code=404, detail="Task not found") |
| |
| task = generation_tasks[task_id] |
| |
| if task.status != "completed": |
| raise HTTPException(status_code=400, detail="Generation not completed") |
| |
| if not task.download_url: |
| raise HTTPException(status_code=404, detail="Download file not available") |
| |
| if not os.path.exists(task.download_url): |
| raise HTTPException(status_code=404, detail="Download file not found") |
| |
| return FileResponse( |
| path=task.download_url, |
| filename=f"generated_project_{task_id}.zip", |
| media_type="application/zip" |
| ) |
|
|
| @app.delete("/api/v1/cleanup/{task_id}") |
| async def cleanup_task(task_id: str): |
| """Clean up task files and data""" |
| |
| if task_id not in generation_tasks: |
| raise HTTPException(status_code=404, detail="Task not found") |
| |
| task = generation_tasks[task_id] |
| |
| |
| if task.download_url and os.path.exists(task.download_url): |
| os.remove(task.download_url) |
| |
| |
| del generation_tasks[task_id] |
| |
| return {"message": "Task cleaned up successfully"} |
|
|
| async def generate_project_background(task_id: str, request: CodeGenerationRequest): |
| """Background task for generating the complete project""" |
| |
| task = generation_tasks[task_id] |
| |
| try: |
| |
| task.status = "processing" |
| task.progress = 10 |
| task.message = "Analyzing requirements..." |
| |
| |
| prompt = create_generation_prompt(request) |
| |
| |
| task.progress = 30 |
| task.message = "Generating application structure..." |
| |
| |
| generated_code = model_manager.generate_code(prompt, max_tokens=1024) |
| |
| |
| task.progress = 60 |
| task.message = "Processing generated code..." |
| |
| |
| project_files = parse_generated_code(generated_code, request) |
| |
| |
| task.progress = 80 |
| task.message = "Creating project files..." |
| |
| |
| zip_path = create_project_zip(task_id, project_files, request) |
| |
| |
| task.status = "completed" |
| task.progress = 100 |
| task.message = "Project generated successfully" |
| task.generated_files = {name: "Generated" for name in project_files.keys()} |
| task.download_url = zip_path |
| |
| except Exception as e: |
| logger.error(f"Generation failed for task {task_id}: {e}") |
| task.status = "failed" |
| task.error = str(e) |
| task.message = "Generation failed" |
|
|
| def create_generation_prompt(request: CodeGenerationRequest) -> str: |
| """Create the prompt for the model""" |
| |
| prompt_parts = [ |
| f"Description: {request.description}", |
| f"Framework: {request.framework}", |
| f"Language: {request.language}", |
| ] |
| |
| if request.requirements: |
| prompt_parts.append("Requirements:") |
| for req in request.requirements: |
| prompt_parts.append(f"- {req}") |
| |
| if request.project_name: |
| prompt_parts.append(f"Project Name: {request.project_name}") |
| |
| prompt_parts.append("Generate the complete backend application with all necessary files:") |
| |
| return "\n".join(prompt_parts) |
|
|
| def parse_generated_code(generated_code: str, request: CodeGenerationRequest) -> Dict[str, str]: |
| """Parse the generated code into individual files""" |
| |
| files = {} |
| |
| |
| lines = generated_code.split('\n') |
| current_file = None |
| current_content = [] |
| |
| for line in lines: |
| if line.startswith('--- ') and line.endswith(' ---'): |
| |
| if current_file: |
| files[current_file] = '\n'.join(current_content) |
| |
| |
| current_file = line.replace('--- ', '').replace(' ---', '').strip() |
| current_content = [] |
| |
| elif current_file and not line.startswith('--- End ---'): |
| current_content.append(line) |
| |
| |
| if current_file and current_content: |
| files[current_file] = '\n'.join(current_content) |
| |
| |
| if not files: |
| files = create_fallback_structure(request) |
| |
| return files |
|
|
| def create_fallback_structure(request: CodeGenerationRequest) -> Dict[str, str]: |
| """Create a basic project structure if parsing fails""" |
| |
| if request.framework.lower() == 'fastapi': |
| return { |
| 'main.py': f'''from fastapi import FastAPI |
| |
| app = FastAPI(title="{request.description}") |
| |
| @app.get("/") |
| async def root(): |
| return {{"message": "Hello from {request.description}"}} |
| |
| @app.get("/health") |
| async def health(): |
| return {{"status": "OK"}} |
| ''', |
| 'requirements.txt': '''fastapi==0.104.1 |
| uvicorn[standard]==0.24.0''' |
| } |
| |
| elif request.framework.lower() == 'express': |
| return { |
| 'app.js': f'''const express = require('express'); |
| const app = express(); |
| |
| app.get('/', (req, res) => {{ |
| res.json({{ message: 'Hello from {request.description}' }}); |
| }}); |
| |
| app.get('/health', (req, res) => {{ |
| res.json({{ status: 'OK' }}); |
| }}); |
| |
| const PORT = process.env.PORT || 3000; |
| app.listen(PORT, () => {{ |
| console.log(`Server running on port ${{PORT}}`); |
| }}); |
| ''', |
| 'package.json': json.dumps({ |
| "name": request.project_name or "generated-backend", |
| "version": "1.0.0", |
| "main": "app.js", |
| "dependencies": { |
| "express": "^4.18.2" |
| } |
| }, indent=2) |
| } |
| |
| else: |
| return { |
| 'README.md': f'# {request.description}\n\nGenerated backend application using {request.framework}' |
| } |
|
|
| def create_project_zip(task_id: str, files: Dict[str, str], request: CodeGenerationRequest) -> str: |
| """Create a ZIP file containing all project files""" |
| |
| |
| temp_dir = tempfile.gettempdir() |
| zip_path = os.path.join(temp_dir, f"project_{task_id}.zip") |
| |
| project_name = request.project_name or f"generated_{request.framework}_app" |
| |
| with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: |
| for filename, content in files.items(): |
| |
| arcname = f"{project_name}/{filename}" |
| zipf.writestr(arcname, content) |
| |
| |
| setup_instructions = get_setup_instructions(request.framework) |
| zipf.writestr(f"{project_name}/SETUP.md", setup_instructions) |
| |
| return zip_path |
|
|
| def get_setup_instructions(framework: str) -> str: |
| """Get setup instructions for the framework""" |
| |
| instructions = { |
| 'fastapi': '''# Setup Instructions |
| |
| 1. Install dependencies: |
| ```bash |
| pip install -r requirements.txt |
| ``` |
| |
| 2. Run the application: |
| ```bash |
| uvicorn main:app --reload |
| ``` |
| |
| 3. Access the API: |
| - API: http://localhost:8000 |
| - Docs: http://localhost:8000/docs |
| ''', |
| 'express': '''# Setup Instructions |
| |
| 1. Install dependencies: |
| ```bash |
| npm install |
| ``` |
| |
| 2. Run the application: |
| ```bash |
| node app.js |
| ``` |
| |
| 3. Access the API: |
| - API: http://localhost:3000 |
| ''', |
| 'django': '''# Setup Instructions |
| |
| 1. Install dependencies: |
| ```bash |
| pip install -r requirements.txt |
| ``` |
| |
| 2. Run migrations: |
| ```bash |
| python manage.py migrate |
| ``` |
| |
| 3. Run the application: |
| ```bash |
| python manage.py runserver |
| ``` |
| |
| 4. Access the API: |
| - API: http://localhost:8000 |
| - Admin: http://localhost:8000/admin |
| ''', |
| 'flask': '''# Setup Instructions |
| |
| 1. Install dependencies: |
| ```bash |
| pip install -r requirements.txt |
| ``` |
| |
| 2. Run the application: |
| ```bash |
| python run.py |
| ``` |
| |
| 3. Access the API: |
| - API: http://localhost:5000 |
| ''' |
| } |
| |
| return instructions.get(framework, '# Setup Instructions\n\nRefer to the framework documentation for setup instructions.') |
|
|
| |
| @app.get("/api/v1/frameworks") |
| async def list_supported_frameworks(): |
| """List supported frameworks and languages""" |
| return { |
| "frameworks": [ |
| { |
| "name": "fastapi", |
| "language": "python", |
| "description": "Modern, fast, web framework for building APIs" |
| }, |
| { |
| "name": "express", |
| "language": "javascript", |
| "description": "Fast, unopinionated web framework for Node.js" |
| }, |
| { |
| "name": "django", |
| "language": "python", |
| "description": "High-level Python web framework" |
| }, |
| { |
| "name": "flask", |
| "language": "python", |
| "description": "Lightweight WSGI web application framework" |
| } |
| ] |
| } |
|
|
| @app.get("/api/v1/examples") |
| async def get_example_requests(): |
| """Get example generation requests""" |
| return { |
| "examples": [ |
| { |
| "name": "E-commerce API", |
| "request": { |
| "description": "Complete e-commerce backend with user management and product catalog", |
| "framework": "fastapi", |
| "language": "python", |
| "requirements": [ |
| "User registration and authentication", |
| "Product CRUD operations", |
| "Shopping cart functionality", |
| "Order management", |
| "Payment processing integration" |
| ] |
| } |
| }, |
| { |
| "name": "Task Management System", |
| "request": { |
| "description": "Task management system with team collaboration", |
| "framework": "express", |
| "language": "javascript", |
| "requirements": [ |
| "User authentication with JWT", |
| "Task CRUD operations", |
| "Team and project management", |
| "Real-time notifications", |
| "File attachments" |
| ] |
| } |
| }, |
| { |
| "name": "Blog Platform", |
| "request": { |
| "description": "Blog platform with content management", |
| "framework": "django", |
| "language": "python", |
| "requirements": [ |
| "Article management", |
| "User comments and ratings", |
| "Category and tag system", |
| "SEO optimization", |
| "Media file handling" |
| ] |
| } |
| } |
| ] |
| } |
|
|
| if __name__ == "__main__": |
| import uvicorn |
| uvicorn.run( |
| "api_service:app", |
| host="0.0.0.0", |
| port=8000, |
| reload=True |
| ) |
|
|