| from fastapi import FastAPI, HTTPException |
| from fastapi.middleware.cors import CORSMiddleware |
| from contextlib import asynccontextmanager |
| from typing import Dict, Any |
| from src.core.llm_engine import LLMEngine |
| from src.ml.edge_case_detector import EdgeCaseDetector |
| from src.core.code_generator import SeleniumGenerator |
| from src.api.models import GenerateRequest, TestSuiteResponse, CodeGenRequest, CodeResponse |
| import uvicorn |
| import uuid |
| import os |
| from loguru import logger |
|
|
| |
| ml_resources: Dict[str, Any] = {} |
|
|
| @asynccontextmanager |
| async def lifespan(app: FastAPI): |
| logger.info("⚡ System Startup: Loading AI Engines...") |
| try: |
| ml_resources["llm"] = LLMEngine() |
| ml_resources["ml"] = EdgeCaseDetector() |
| ml_resources["codegen"] = SeleniumGenerator() |
| logger.info("✅ Engines Online.") |
| except Exception as e: |
| logger.critical(f"❌ Engine Startup Failed: {e}") |
| raise e |
| yield |
| ml_resources.clear() |
| logger.info("🛑 System Shutdown.") |
|
|
| |
| app = FastAPI( |
| title="Zeta AI API", |
| version="1.0.0", |
| lifespan=lifespan |
| ) |
|
|
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| @app.get("/health") |
| async def health_check(): |
| return { |
| "status": "active", |
| "engines_loaded": list(ml_resources.keys()) |
| } |
|
|
| @app.post("/generate", response_model=TestSuiteResponse) |
| async def generate_tests(request: GenerateRequest): |
| logger.info(f"Processing generation request ({len(request.requirements_text)} chars)") |
| |
| if "llm" not in ml_resources: |
| raise HTTPException(status_code=503, detail="AI Engines not ready") |
|
|
| try: |
| |
| llm_engine: LLMEngine = ml_resources["llm"] |
| raw_tests = await llm_engine.generate_test_cases(request.requirements_text) |
| |
| |
| |
| for test in raw_tests: |
| if "text" not in test: |
| |
| test["text"] = f"{test.get('title', '')} {' '.join(test.get('steps', []))}" |
| |
| ml_engine: EdgeCaseDetector = ml_resources["ml"] |
| |
| |
| analysis_objects = await ml_engine.analyze_complexity(raw_tests) |
| |
| |
| |
| final_test_cases = [] |
| for original, analysis in zip(raw_tests, analysis_objects): |
| |
| merged = original.copy() |
| |
| |
| analysis_dict = analysis.model_dump() |
| merged["risk_analysis"] = { |
| "is_edge_case": analysis_dict["is_edge_case"], |
| "risk_level": analysis_dict["risk_level"], |
| "complexity_score": analysis_dict["complexity_score"], |
| "risk_sources": analysis_dict["risk_sources"] |
| } |
| final_test_cases.append(merged) |
|
|
| return TestSuiteResponse( |
| suite_id=str(uuid.uuid4()), |
| test_cases=final_test_cases, |
| meta={"source": "Gemini 2.5", "ml_validation": True} |
| ) |
| |
| except Exception as e: |
| logger.error(f"Generation logic failed: {e}") |
| |
| raise HTTPException(status_code=500, detail=f"Internal Error: {str(e)}") |
|
|
| @app.post("/codegen", response_model=CodeResponse) |
| async def generate_code(request: CodeGenRequest): |
| if "codegen" not in ml_resources: |
| raise HTTPException(status_code=503, detail="Codegen Engine not ready") |
| |
| try: |
| codegen_engine: SeleniumGenerator = ml_resources["codegen"] |
| code = codegen_engine.generate_test_script(request.test_plan) |
| return CodeResponse( |
| filename=f"test_{uuid.uuid4().hex[:8]}.py", |
| python_code=code |
| ) |
| except Exception as e: |
| logger.error(f"Codegen failed: {e}") |
| raise HTTPException(status_code=500, detail="Code generation failed") |
|
|
| if __name__ == "__main__": |
| port = int(os.getenv("PORT", 8000)) |
| uvicorn.run("src.api.main:app", host="0.0.0.0", port=port, reload=True) |