|
|
from logging import Logger |
|
|
import os |
|
|
from datetime import datetime |
|
|
from typing import Dict, List, Optional |
|
|
from dotenv import load_dotenv |
|
|
from langchain_ollama import OllamaLLM |
|
|
from langgraph.graph import END, StateGraph |
|
|
from models import AgentState, DiagramType |
|
|
from config import Config |
|
|
from langchain_core.prompts import ChatPromptTemplate |
|
|
from file_manager import FileManager |
|
|
from agents.analysis import ( |
|
|
EntitiesAnalysis, |
|
|
ActorsAnalysis, |
|
|
SequenceAnalysis, |
|
|
StateAnalysis, |
|
|
ArchitectureAnalysis, |
|
|
DeploymentAnalysis |
|
|
) |
|
|
from agents.code import ( |
|
|
ClassDiagramGenerator, |
|
|
UseCaseDiagramGenerator, |
|
|
SequenceDiagramGenerator, |
|
|
ActivityDiagramGenerator, |
|
|
ComponentDiagramGenerator, |
|
|
DeploymentDiagramGenerator, |
|
|
StateDiagramGenerator, |
|
|
TimingDiagramGenerator, |
|
|
ObjectDiagramGenerator |
|
|
) |
|
|
from fastapi import FastAPI, HTTPException |
|
|
from fastapi.responses import StreamingResponse |
|
|
from fastapi.middleware.cors import CORSMiddleware |
|
|
from pydantic import BaseModel |
|
|
import asyncio |
|
|
from langchain_core.callbacks import StreamingStdOutCallbackHandler |
|
|
import json |
|
|
|
|
|
|
|
|
load_dotenv() |
|
|
|
|
|
|
|
|
app = FastAPI() |
|
|
|
|
|
|
|
|
app.add_middleware( |
|
|
CORSMiddleware, |
|
|
allow_origins=["*"], |
|
|
allow_credentials=True, |
|
|
allow_methods=["*"], |
|
|
allow_headers=["*"], |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
class DiagramRequest(BaseModel): |
|
|
project_name: str |
|
|
project_description: str |
|
|
selected_diagrams: List[int] |
|
|
output_dir: Optional[str] = "output" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.post("/generate-diagrams") |
|
|
async def generate_diagrams(request: DiagramRequest): |
|
|
try: |
|
|
initial_state = AgentState( |
|
|
project_name=request.project_name, |
|
|
project_description=request.project_description, |
|
|
output_dir=request.output_dir, |
|
|
selected_diagrams=request.selected_diagrams, |
|
|
entities_classes="", |
|
|
actors_use_cases="", |
|
|
sequence_interactions="", |
|
|
class_diagram="", |
|
|
use_case_diagram="", |
|
|
sequence_diagram="", |
|
|
activity_diagram="", |
|
|
component_diagram="", |
|
|
deployment_diagram="", |
|
|
state_diagram="", |
|
|
timing_diagram="", |
|
|
object_diagram="" |
|
|
) |
|
|
|
|
|
|
|
|
diagram_requirements = { |
|
|
DiagramType.CLASS: ["extract_entities"], |
|
|
DiagramType.USE_CASE: ["extract_actors"], |
|
|
DiagramType.SEQUENCE: ["extract_actors", "extract_sequence"], |
|
|
DiagramType.OBJECT: ["extract_entities"], |
|
|
DiagramType.ACTIVITY: ["extract_actors"], |
|
|
DiagramType.COMPONENT: ["extract_entities", "extract_architecture"], |
|
|
DiagramType.DEPLOYMENT: ["extract_architecture", "extract_deployment"], |
|
|
DiagramType.STATE: ["extract_entities", "extract_sequence", "extract_states"], |
|
|
DiagramType.TIMING: ["extract_sequence"] |
|
|
} |
|
|
|
|
|
|
|
|
analysis_functions = { |
|
|
"extract_entities": EntitiesAnalysis(), |
|
|
"extract_actors": ActorsAnalysis(), |
|
|
"extract_sequence": SequenceAnalysis(), |
|
|
"extract_states": StateAnalysis(), |
|
|
"extract_architecture": ArchitectureAnalysis(), |
|
|
"extract_deployment": DeploymentAnalysis() |
|
|
} |
|
|
|
|
|
generation_functions = { |
|
|
DiagramType.CLASS: ("generate_class", ClassDiagramGenerator()), |
|
|
DiagramType.USE_CASE: ("generate_use_case", UseCaseDiagramGenerator()), |
|
|
DiagramType.SEQUENCE: ("generate_sequence", SequenceDiagramGenerator()), |
|
|
DiagramType.ACTIVITY: ("generate_activity", ActivityDiagramGenerator()), |
|
|
DiagramType.COMPONENT: ("generate_component", ComponentDiagramGenerator()), |
|
|
DiagramType.DEPLOYMENT: ("generate_deployment", DeploymentDiagramGenerator()), |
|
|
DiagramType.STATE: ("generate_state", StateDiagramGenerator()), |
|
|
DiagramType.TIMING: ("generate_timing", TimingDiagramGenerator()), |
|
|
DiagramType.OBJECT: ("generate_object", ObjectDiagramGenerator()) |
|
|
} |
|
|
|
|
|
|
|
|
selected_types = [DiagramType(d) for d in request.selected_diagrams] |
|
|
added_analysis_steps = set() |
|
|
steps = [] |
|
|
|
|
|
for diagram_type in selected_types: |
|
|
required_analysis = diagram_requirements.get(diagram_type, []) |
|
|
for step in required_analysis: |
|
|
if step not in added_analysis_steps: |
|
|
steps.append((step, analysis_functions[step])) |
|
|
added_analysis_steps.add(step) |
|
|
|
|
|
if diagram_type in generation_functions: |
|
|
steps.append(generation_functions[diagram_type]) |
|
|
|
|
|
|
|
|
async def event_stream(): |
|
|
for step_name, step_func in steps: |
|
|
|
|
|
step_type = "analysis" if step_name in analysis_functions else "generation" |
|
|
|
|
|
file_ext = "pu" if step_type == "generation" else "md" |
|
|
yield f'data: {{"type": "step", "step_type": "{step_type}", "file_name": "{step_name}.{file_ext}"}}\n\n' |
|
|
async for chunk in step_func(initial_state): |
|
|
yield f"data: {chunk}\n\n" |
|
|
|
|
|
return StreamingResponse(event_stream(), media_type="text/event-stream") |
|
|
|
|
|
except Exception as e: |
|
|
raise HTTPException(status_code=500, detail=str(e)) |
|
|
|
|
|
|
|
|
|