Skip to content

Commit 99bf6ec

Browse files
Undo Functionality & Version Control
1 parent c5d4fd5 commit 99bf6ec

File tree

11 files changed

+558
-321
lines changed

11 files changed

+558
-321
lines changed

.env

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@ EMBEDDING_MODEL="text-embedding-3-small"
55
EMBEDDING_API_VERSION="2023-05-15"
66
ENDPOINT="https://ai4se-openai.openai.azure.com/"
77
AZURE_OPENAI_API_KEY="VDfaCeEbTyAyPRC3C02mZyyANPxZGBxODmWOpWechSlv7GQ8zmmuJQQJ99AKACI8hq2XJ3w3AAABACOGPYeE"
8-
MONGODB_URI="mongodb://localhost:27017/"

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ Thumbs.db
1919
.env
2020

2121
notes.txt
22-
temp.json
22+
temp.json
23+
user_inputs.txt

README.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- Classifies input as "General" or "Scenario" intelligently.
1111
- Generates detailed scenarios and concise summaries using GPT models.
1212
- Converts extracted domain structures into **PlantUML** diagrams.
13+
- Stores and manages data using **MongoDB**.
1314
- Includes a full test suite for backend routes with **pytest**.
1415

1516
---
@@ -18,10 +19,11 @@
1819

1920
- **Python 3.9+**
2021
- **Flask** (Web Framework)
21-
- **OpenAI API** (Azure variant support)
22-
- **PlantUML** (Diagram generation)
22+
- **OpenAI API** (Azure-compatible)
23+
- **MongoDB** (Database)
24+
- **PlantUML** (Diagram rendering)
25+
- **dotenv** (Environment configuration)
2326
- **pytest** (Testing)
24-
- **dotenv** (Environment management)
2527

2628
---
2729

@@ -54,10 +56,21 @@ EMBEDDING_MODEL="text-embedding-3-small"
5456
EMBEDDING_API_VERSION="2023-05-15"
5557
ENDPOINT="https://your-azure-endpoint/"
5658
AZURE_OPENAI_API_KEY="your-api-key"
59+
MONGO_URI="mongodb://localhost:27017/domain_modelling"
5760
```
5861

5962
### 5. Run the application
6063
```bash
6164
python app.py
6265
```
6366
Visit: http://localhost:5000
67+
68+
### MongoDB Setup
69+
1. Install MongoDB: MongoDB Installation Guide
70+
71+
2. Start MongoDB Server:
72+
73+
```bash
74+
mongod
75+
```
76+
03. Database Connection: The app connects to MongoDB using the URI in .env (MONGO_URI). The database and collections will be created automatically.

src/app.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ def save_project_data():
9090
controller = get_project_controller()
9191
return controller.save_project_data()
9292

93+
@app.route("/undo_project_change", methods=["POST"])
94+
def undo_project_change():
95+
"""Undo project change endpoint."""
96+
controller = get_project_controller()
97+
return controller.undo_project_change()
98+
9399
# Run the application
94100
if __name__ == "__main__":
95101
app.run(debug=True)

src/controller/chat_controller.py

Lines changed: 92 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,135 @@
11
from flask import request, jsonify, session
22
from src.model.llm_service import LLMService
33
from src.model.gpt2 import gpt_v2_interface
4+
from src.model.project_service import ProjectService
45

56
class ChatController:
6-
"""Controller for chat-related operations"""
7+
"""Controller for chat-related operations and version saving"""
78

89
def __init__(self):
910
self.llm_service = LLMService()
11+
self.project_service = ProjectService()
1012

1113
def handle_chat_request(self):
12-
"""Process user input and return domain model with suggestions"""
14+
"""Process user input and generate response with version saving"""
1315
try:
14-
# Get and validate user input
15-
user_input = request.json.get("message", "").strip()
16+
data = request.json
17+
user_input = data.get("message", "").strip()
18+
project_name = data.get("project_name", "").strip()
19+
1620
if not user_input:
1721
return jsonify({"error": "User input is required"}), 400
22+
if not project_name:
23+
return jsonify({"error": "Project name is required to save version"}), 400
24+
25+
# Get the current state before processing new input
26+
# This ensures we always have the latest domain model and PlantUML
27+
project_result, _ = self.project_service.get_project_data(project_name)
28+
current_project_data = project_result.get("project_data", {})
29+
30+
# Get existing domain model description and PlantUML from project data
31+
# These will be used as fallbacks if nothing new is generated
32+
existing_dmd = current_project_data.get("domain_model_description", "Welcome to your new project! Start by describing your domain.")
33+
existing_plant_uml = current_project_data.get("plant_uml", "@startuml\nskinparam monochrome true\ntitle Your New Project\n\nclass ExampleEntity {\n +id: string\n +name: string\n}\n\nnote \"Start building your domain model!\" as N1\n@enduml")
1834

19-
# Add current input to chat history
2035
self.llm_service.add_to_chat_history("user", user_input)
21-
22-
# Get updated chat history after adding the new message
2336
updated_chat_history = self.llm_service.chat_history.get_messages()
24-
25-
# Format chat history as a single string
2637
chat_history_text = "\n".join([
2738
f"{'User' if msg['role'] == 'user' else 'Assistant'}: {msg['content']}"
2839
for msg in updated_chat_history
2940
])
3041

31-
# Determine input type with enhanced analysis
32-
result = self.llm_service.determine_input_type(chat_history_text)
33-
34-
# Extract all classification fields
35-
decision = result.get("decision", False)
36-
is_update = result.get("is_update", False)
37-
is_casual_comment = result.get("is_casual_comment", False)
38-
suggestions = result.get("suggestions", [])
42+
classification_result = self.llm_service.determine_input_type(chat_history_text)
3943

40-
# Format the response from the suggestions array
41-
formatted_suggestions = "\n".join(suggestions) if isinstance(suggestions, list) else suggestions
42-
43-
# Handle each case appropriately
44+
decision = classification_result.get("decision", False)
45+
is_casual_comment = classification_result.get("is_casual_comment", False)
46+
suggestions = classification_result.get("suggestions", [])
47+
assistant_response = "\n".join(suggestions) if isinstance(suggestions, list) else suggestions
48+
49+
# Set initial state using existing values to ensure we never store nulls
50+
current_dmd = self.llm_service.get_current_domain_model_description() or existing_dmd
51+
current_plant_uml = existing_plant_uml
52+
4453
if is_casual_comment:
45-
# Casual comment - don't regenerate the domain model
46-
self.llm_service.add_to_chat_history("assistant", formatted_suggestions)
54+
self.llm_service.add_to_chat_history("assistant", assistant_response)
55+
56+
# Use existing domain model and PlantUML (already set above)
57+
# If DMD exists but PlantUML doesn't, generate PlantUML
58+
if current_dmd and not current_plant_uml:
59+
client = self.llm_service.client
60+
current_plant_uml = gpt_v2_interface(current_dmd, client)
61+
62+
self.project_service.save_version(
63+
project_name,
64+
user_input,
65+
assistant_response,
66+
current_dmd,
67+
current_plant_uml
68+
)
4769
return jsonify({
48-
"response": formatted_suggestions,
49-
"history": self.llm_service.get_chat_history()
70+
"response": assistant_response,
71+
"history": self.llm_service.get_chat_history(),
72+
"domain_model_description": current_dmd,
73+
"plant_uml": current_plant_uml
5074
})
5175

52-
elif decision:
53-
# Enough information for domain modeling (either new model or update)
54-
domain_model_description = self.llm_service.generate_domain_model_description(chat_history_text)
76+
elif decision: # Enough information for domain modeling (new or update)
77+
new_dmd = self.llm_service.generate_domain_model_description(chat_history_text)
78+
self.llm_service.add_to_chat_history("assistant", assistant_response)
5579

56-
# Add response to chat history
57-
self.llm_service.add_to_chat_history("assistant", formatted_suggestions)
80+
# Generate PlantUML for the new/updated DMD
81+
client = self.llm_service.client
82+
new_plant_uml = ""
83+
if new_dmd:
84+
new_plant_uml = gpt_v2_interface(new_dmd, client)
85+
else:
86+
new_dmd = current_dmd # Fallback to existing DMD
87+
new_plant_uml = current_plant_uml # Fallback to existing PlantUML
88+
89+
self.project_service.save_version(
90+
project_name,
91+
user_input,
92+
assistant_response,
93+
new_dmd,
94+
new_plant_uml
95+
)
5896

5997
return jsonify({
60-
"domain_model_description": domain_model_description,
61-
"suggestion": formatted_suggestions
98+
"domain_model_description": new_dmd,
99+
"suggestion": assistant_response,
100+
"plant_uml": new_plant_uml
62101
})
63102

64-
else:
65-
# Not enough info for domain modeling
66-
self.llm_service.add_to_chat_history("assistant", formatted_suggestions)
103+
else: # Not enough info for domain modeling
104+
self.llm_service.add_to_chat_history("assistant", assistant_response)
105+
106+
# Use existing domain model and PlantUML
107+
# If we have a domain model but no PlantUML, generate it
108+
if current_dmd and not current_plant_uml:
109+
client = self.llm_service.client
110+
current_plant_uml = gpt_v2_interface(current_dmd, client)
111+
112+
self.project_service.save_version(
113+
project_name,
114+
user_input,
115+
assistant_response,
116+
current_dmd,
117+
current_plant_uml
118+
)
67119

68120
return jsonify({
69-
"response": formatted_suggestions,
70-
"history": self.llm_service.get_chat_history()
121+
"response": assistant_response,
122+
"history": self.llm_service.get_chat_history(),
123+
"domain_model_description": current_dmd,
124+
"plant_uml": current_plant_uml
71125
})
72126

73127
except Exception as e:
74128
print(f"Error in chat request: {e}")
75129
import traceback
76-
traceback.print_exc() # Add traceback for better error debugging
130+
traceback.print_exc()
77131
return jsonify({"error": "An unexpected error occurred"}), 500
78132

79-
# Remove submit_name method
80-
81133
def generate_uml(self):
82134
"""Generate UML diagram from domain model description"""
83135
try:

src/controller/project_controller.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from src.model.project_service import ProjectService
33

44
class ProjectController:
5-
"""Controller for project management operations (simplified model)"""
5+
"""Controller for project management operations"""
66

77
def __init__(self):
88
self.project_service = ProjectService()
@@ -58,11 +58,38 @@ def save_project_data(self):
5858
plant_uml = data.get("plant_uml")
5959
chat_history = data.get("chat_history")
6060

61-
result, status_code = self.project_service.save_project_data(
62-
project_name, domain_model_description, plant_uml, chat_history
61+
# Extract last messages from chat history if available
62+
user_input = None
63+
assistant = None
64+
if chat_history and len(chat_history) >= 2:
65+
# Assuming the last user message and response are at the end of the chat history
66+
for i in range(len(chat_history)-1, -1, -1):
67+
if chat_history[i]["role"] == "assistant" and assistant is None:
68+
assistant = chat_history[i]["content"]
69+
elif chat_history[i]["role"] == "user" and user_input is None:
70+
user_input = chat_history[i]["content"]
71+
if user_input and assistant:
72+
break
73+
74+
result, status_code = self.project_service.save_version(
75+
project_name, user_input, assistant, domain_model_description, plant_uml
6376
)
6477

6578
return jsonify(result), status_code
6679
except Exception as e:
6780
print(f"Error in save_project_data: {e}")
68-
return jsonify({"error": "An unexpected error occurred."}), 500
81+
return jsonify({"error": "An unexpected error occurred."}), 500
82+
83+
def undo_project_change(self):
84+
"""Handle request to undo the latest version for a project."""
85+
try:
86+
data = request.json
87+
project_name = data.get("project_name", "").strip()
88+
if not project_name:
89+
return jsonify({"error": "Project name is required."}), 400
90+
91+
result, status_code = self.project_service.undo_version(project_name)
92+
return jsonify(result), status_code
93+
except Exception as e:
94+
print(f"Error in undo_project_change controller: {e}")
95+
return jsonify({"error": "An unexpected error occurred while undoing version."}), 500

0 commit comments

Comments
 (0)