Mohammed Foud commited on
Commit
f0c738b
·
1 Parent(s): 97a814a

Add application file

Browse files
Files changed (4) hide show
  1. Dockerfile +1 -1
  2. app.py +150 -65
  3. main.py +0 -153
  4. run.sh +1 -1
Dockerfile CHANGED
@@ -10,4 +10,4 @@ COPY --chown=user ./requirements.txt requirements.txt
10
  RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
 
12
  COPY --chown=user . /app
13
- CMD ["gunicorn", "--bind", "0.0.0.0:7860", "app:app"]
 
10
  RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
 
12
  COPY --chown=user . /app
13
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py CHANGED
@@ -1,68 +1,153 @@
1
- from flask import Flask, jsonify, render_template, request, Response, stream_with_context
2
- from research_generator import ResearchGenerator
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  import asyncio
 
4
  import json
5
- from langchain_core.output_parsers import StrOutputParser
6
- from langchain_core.prompts import ChatPromptTemplate
7
 
8
- app = Flask(__name__)
9
- generator = ResearchGenerator()
10
-
11
- @app.route('/')
12
- def index():
13
- return {}
14
-
15
- async def process_state(state):
16
- if "index" in state and state["index"]:
17
- # If we have an index, process it with the LLM
18
- prompt = ChatPromptTemplate.from_template("""
19
- Process the following research state:
20
- {state}
21
- """)
22
- chain = prompt | generator.llm | StrOutputParser()
23
-
24
- async for chunk in chain.astream({"state": json.dumps(state)}):
25
- yield f"data: {json.dumps({'chunk': chunk, 'state': state})}\n\n"
26
- else:
27
- # If we're generating the index, stream it directly
28
- yield f"data: {json.dumps({'state': state})}\n\n"
29
-
30
- @app.route('/generate', methods=['POST'])
31
- def generate_research():
32
- data = request.get_json()
33
- subject = data.get('subject')
34
- if not subject:
35
- return jsonify({'error': 'Subject is required'}), 400
36
-
37
- async def generate():
38
- generator = ResearchGenerator()
39
- async for state in generator.astream({
40
- "subject": subject,
41
- "index": [],
42
- "content": {},
43
- "current_step": 0
44
- }):
45
- async for chunk in process_state(state):
46
- yield chunk
47
-
48
- def sync_generate():
49
- loop = asyncio.new_event_loop()
50
- asyncio.set_event_loop(loop)
51
- try:
52
- async_gen = generate()
53
- while True:
54
- try:
55
- chunk = loop.run_until_complete(async_gen.__anext__())
56
- yield chunk
57
- except StopAsyncIteration:
58
- break
59
- finally:
60
- loop.close()
61
-
62
- return Response(
63
- stream_with_context(sync_generate()),
64
- mimetype='text/event-stream'
65
- )
66
-
67
- if __name__ == '__main__':
68
- app.run(debug=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from logging import Logger
2
+ import os
3
+ from datetime import datetime
4
+ from typing import Dict, List, Optional
5
+ from dotenv import load_dotenv
6
+ from langchain_ollama import OllamaLLM
7
+ from langgraph.graph import END, StateGraph
8
+ from models import AgentState, DiagramType
9
+ from config import Config
10
+ from langchain_core.prompts import ChatPromptTemplate
11
+ from file_manager import FileManager
12
+ from agents.analysis import (
13
+ EntitiesAnalysis,
14
+ ActorsAnalysis,
15
+ SequenceAnalysis,
16
+ StateAnalysis,
17
+ ArchitectureAnalysis,
18
+ DeploymentAnalysis
19
+ )
20
+ from agents.code import (
21
+ ClassDiagramGenerator,
22
+ UseCaseDiagramGenerator,
23
+ SequenceDiagramGenerator,
24
+ ActivityDiagramGenerator,
25
+ ComponentDiagramGenerator,
26
+ DeploymentDiagramGenerator,
27
+ StateDiagramGenerator,
28
+ TimingDiagramGenerator,
29
+ ObjectDiagramGenerator
30
+ )
31
+ from fastapi import FastAPI, HTTPException
32
+ from fastapi.responses import StreamingResponse
33
+ from fastapi.middleware.cors import CORSMiddleware
34
+ from pydantic import BaseModel
35
  import asyncio
36
+ from langchain_core.callbacks import StreamingStdOutCallbackHandler
37
  import json
 
 
38
 
39
+ # Load environment variables
40
+ load_dotenv()
41
+
42
+ # Initialize FastAPI app
43
+ app = FastAPI()
44
+
45
+ # Add CORS middleware configuration
46
+ app.add_middleware(
47
+ CORSMiddleware,
48
+ allow_origins=["*"],
49
+ allow_credentials=True,
50
+ allow_methods=["*"],
51
+ allow_headers=["*"],
52
+ )
53
+
54
+
55
+ # Request model
56
+ class DiagramRequest(BaseModel):
57
+ project_name: str
58
+ project_description: str
59
+ selected_diagrams: List[int]
60
+ output_dir: Optional[str] = "output"
61
+
62
+
63
+
64
+
65
+ @app.post("/generate-diagrams")
66
+ async def generate_diagrams(request: DiagramRequest):
67
+ try:
68
+ initial_state = AgentState(
69
+ project_name=request.project_name,
70
+ project_description=request.project_description,
71
+ output_dir=request.output_dir,
72
+ selected_diagrams=request.selected_diagrams,
73
+ entities_classes="",
74
+ actors_use_cases="",
75
+ sequence_interactions="",
76
+ class_diagram="",
77
+ use_case_diagram="",
78
+ sequence_diagram="",
79
+ activity_diagram="",
80
+ component_diagram="",
81
+ deployment_diagram="",
82
+ state_diagram="",
83
+ timing_diagram="",
84
+ object_diagram=""
85
+ )
86
+
87
+
88
+ diagram_requirements = {
89
+ DiagramType.CLASS: ["extract_entities"],
90
+ DiagramType.USE_CASE: ["extract_actors"],
91
+ DiagramType.SEQUENCE: ["extract_actors", "extract_sequence"],
92
+ DiagramType.OBJECT: ["extract_entities"],
93
+ DiagramType.ACTIVITY: ["extract_actors"],
94
+ DiagramType.COMPONENT: ["extract_entities", "extract_architecture"],
95
+ DiagramType.DEPLOYMENT: ["extract_architecture", "extract_deployment"],
96
+ DiagramType.STATE: ["extract_entities", "extract_sequence", "extract_states"],
97
+ DiagramType.TIMING: ["extract_sequence"]
98
+ }
99
+
100
+
101
+ analysis_functions = {
102
+ "extract_entities": EntitiesAnalysis(),
103
+ "extract_actors": ActorsAnalysis(),
104
+ "extract_sequence": SequenceAnalysis(),
105
+ "extract_states": StateAnalysis(),
106
+ "extract_architecture": ArchitectureAnalysis(),
107
+ "extract_deployment": DeploymentAnalysis()
108
+ }
109
+
110
+ generation_functions = {
111
+ DiagramType.CLASS: ("generate_class", ClassDiagramGenerator()),
112
+ DiagramType.USE_CASE: ("generate_use_case", UseCaseDiagramGenerator()),
113
+ DiagramType.SEQUENCE: ("generate_sequence", SequenceDiagramGenerator()),
114
+ DiagramType.ACTIVITY: ("generate_activity", ActivityDiagramGenerator()),
115
+ DiagramType.COMPONENT: ("generate_component", ComponentDiagramGenerator()),
116
+ DiagramType.DEPLOYMENT: ("generate_deployment", DeploymentDiagramGenerator()),
117
+ DiagramType.STATE: ("generate_state", StateDiagramGenerator()),
118
+ DiagramType.TIMING: ("generate_timing", TimingDiagramGenerator()),
119
+ DiagramType.OBJECT: ("generate_object", ObjectDiagramGenerator())
120
+ }
121
+
122
+
123
+ selected_types = [DiagramType(d) for d in request.selected_diagrams]
124
+ added_analysis_steps = set()
125
+ steps = []
126
+
127
+ for diagram_type in selected_types:
128
+ required_analysis = diagram_requirements.get(diagram_type, [])
129
+ for step in required_analysis:
130
+ if step not in added_analysis_steps:
131
+ steps.append((step, analysis_functions[step]))
132
+ added_analysis_steps.add(step)
133
+
134
+ if diagram_type in generation_functions:
135
+ steps.append(generation_functions[diagram_type])
136
+
137
+
138
+ async def event_stream():
139
+ for step_name, step_func in steps:
140
+ # Determine if it's an analysis step or generation step
141
+ step_type = "analysis" if step_name in analysis_functions else "generation"
142
+ # Determine file extension based on step type
143
+ file_ext = "pu" if step_type == "generation" else "md"
144
+ yield f'data: {{"type": "step", "step_type": "{step_type}", "file_name": "{step_name}.{file_ext}"}}\n\n'
145
+ async for chunk in step_func(initial_state):
146
+ yield f"data: {chunk}\n\n"
147
+
148
+ return StreamingResponse(event_stream(), media_type="text/event-stream")
149
+
150
+ except Exception as e:
151
+ raise HTTPException(status_code=500, detail=str(e))
152
+
153
+
main.py DELETED
@@ -1,153 +0,0 @@
1
- from logging import Logger
2
- import os
3
- from datetime import datetime
4
- from typing import Dict, List, Optional
5
- from dotenv import load_dotenv
6
- from langchain_ollama import OllamaLLM
7
- from langgraph.graph import END, StateGraph
8
- from models import AgentState, DiagramType
9
- from config import Config
10
- from langchain_core.prompts import ChatPromptTemplate
11
- from file_manager import FileManager
12
- from agents.analysis import (
13
- EntitiesAnalysis,
14
- ActorsAnalysis,
15
- SequenceAnalysis,
16
- StateAnalysis,
17
- ArchitectureAnalysis,
18
- DeploymentAnalysis
19
- )
20
- from agents.code import (
21
- ClassDiagramGenerator,
22
- UseCaseDiagramGenerator,
23
- SequenceDiagramGenerator,
24
- ActivityDiagramGenerator,
25
- ComponentDiagramGenerator,
26
- DeploymentDiagramGenerator,
27
- StateDiagramGenerator,
28
- TimingDiagramGenerator,
29
- ObjectDiagramGenerator
30
- )
31
- from fastapi import FastAPI, HTTPException
32
- from fastapi.responses import StreamingResponse
33
- from fastapi.middleware.cors import CORSMiddleware
34
- from pydantic import BaseModel
35
- import asyncio
36
- from langchain_core.callbacks import StreamingStdOutCallbackHandler
37
- import json
38
-
39
- # Load environment variables
40
- load_dotenv()
41
-
42
- # Initialize FastAPI app
43
- app = FastAPI()
44
-
45
- # Add CORS middleware configuration
46
- app.add_middleware(
47
- CORSMiddleware,
48
- allow_origins=["*"],
49
- allow_credentials=True,
50
- allow_methods=["*"],
51
- allow_headers=["*"],
52
- )
53
-
54
-
55
- # Request model
56
- class DiagramRequest(BaseModel):
57
- project_name: str
58
- project_description: str
59
- selected_diagrams: List[int]
60
- output_dir: Optional[str] = "output"
61
-
62
-
63
-
64
-
65
- @app.post("/generate-diagrams")
66
- async def generate_diagrams(request: DiagramRequest):
67
- try:
68
- initial_state = AgentState(
69
- project_name=request.project_name,
70
- project_description=request.project_description,
71
- output_dir=request.output_dir,
72
- selected_diagrams=request.selected_diagrams,
73
- entities_classes="",
74
- actors_use_cases="",
75
- sequence_interactions="",
76
- class_diagram="",
77
- use_case_diagram="",
78
- sequence_diagram="",
79
- activity_diagram="",
80
- component_diagram="",
81
- deployment_diagram="",
82
- state_diagram="",
83
- timing_diagram="",
84
- object_diagram=""
85
- )
86
-
87
-
88
- diagram_requirements = {
89
- DiagramType.CLASS: ["extract_entities"],
90
- DiagramType.USE_CASE: ["extract_actors"],
91
- DiagramType.SEQUENCE: ["extract_actors", "extract_sequence"],
92
- DiagramType.OBJECT: ["extract_entities"],
93
- DiagramType.ACTIVITY: ["extract_actors"],
94
- DiagramType.COMPONENT: ["extract_entities", "extract_architecture"],
95
- DiagramType.DEPLOYMENT: ["extract_architecture", "extract_deployment"],
96
- DiagramType.STATE: ["extract_entities", "extract_sequence", "extract_states"],
97
- DiagramType.TIMING: ["extract_sequence"]
98
- }
99
-
100
-
101
- analysis_functions = {
102
- "extract_entities": EntitiesAnalysis(),
103
- "extract_actors": ActorsAnalysis(),
104
- "extract_sequence": SequenceAnalysis(),
105
- "extract_states": StateAnalysis(),
106
- "extract_architecture": ArchitectureAnalysis(),
107
- "extract_deployment": DeploymentAnalysis()
108
- }
109
-
110
- generation_functions = {
111
- DiagramType.CLASS: ("generate_class", ClassDiagramGenerator()),
112
- DiagramType.USE_CASE: ("generate_use_case", UseCaseDiagramGenerator()),
113
- DiagramType.SEQUENCE: ("generate_sequence", SequenceDiagramGenerator()),
114
- DiagramType.ACTIVITY: ("generate_activity", ActivityDiagramGenerator()),
115
- DiagramType.COMPONENT: ("generate_component", ComponentDiagramGenerator()),
116
- DiagramType.DEPLOYMENT: ("generate_deployment", DeploymentDiagramGenerator()),
117
- DiagramType.STATE: ("generate_state", StateDiagramGenerator()),
118
- DiagramType.TIMING: ("generate_timing", TimingDiagramGenerator()),
119
- DiagramType.OBJECT: ("generate_object", ObjectDiagramGenerator())
120
- }
121
-
122
-
123
- selected_types = [DiagramType(d) for d in request.selected_diagrams]
124
- added_analysis_steps = set()
125
- steps = []
126
-
127
- for diagram_type in selected_types:
128
- required_analysis = diagram_requirements.get(diagram_type, [])
129
- for step in required_analysis:
130
- if step not in added_analysis_steps:
131
- steps.append((step, analysis_functions[step]))
132
- added_analysis_steps.add(step)
133
-
134
- if diagram_type in generation_functions:
135
- steps.append(generation_functions[diagram_type])
136
-
137
-
138
- async def event_stream():
139
- for step_name, step_func in steps:
140
- # Determine if it's an analysis step or generation step
141
- step_type = "analysis" if step_name in analysis_functions else "generation"
142
- # Determine file extension based on step type
143
- file_ext = "pu" if step_type == "generation" else "md"
144
- yield f'data: {{"type": "step", "step_type": "{step_type}", "file_name": "{step_name}.{file_ext}"}}\n\n'
145
- async for chunk in step_func(initial_state):
146
- yield f"data: {chunk}\n\n"
147
-
148
- return StreamingResponse(event_stream(), media_type="text/event-stream")
149
-
150
- except Exception as e:
151
- raise HTTPException(status_code=500, detail=str(e))
152
-
153
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
run.sh CHANGED
@@ -1 +1 @@
1
- uvicorn main:app --reload
 
1
+ uvicorn app:app --reload