Skip to content

Commit 173bf08

Browse files
committed
[dev] enhance UI and demo logic
1 parent fa0a6a8 commit 173bf08

File tree

6 files changed

+154
-168
lines changed

6 files changed

+154
-168
lines changed

backend/ai-prompts.js

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/schema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const schemaList = [
1515
properties: {
1616
id: {
1717
type: "string",
18-
description: "Unique employee identifier (name in lowercase)."
18+
description: "Unique numerical employee identifier using dot notation for hierarchy (e.g., '1', '1.1', '1.2')."
1919
},
2020
text: {
2121
type: "string",

backend/server.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ async function callOpenAIForRephrase(userText) {
7979

8080
try {
8181
const res = await openai.chat.completions.create({
82-
model: 'gpt-5-nano',
82+
model: 'gpt-4.1-nano',
8383
messages: messages,
8484
});
8585
return res.choices[0].message.content;
@@ -93,7 +93,7 @@ async function callOpenAIForDiagram(userText) {
9393

9494
try {
9595
const res = await openai.chat.completions.create({
96-
model: 'gpt-5-nano',
96+
model: 'gpt-4.1-nano',
9797
messages: messages,
9898
tools: schemaList,
9999
tool_choice: { type: "function", function: { name: "create_org_chart_diagram" } },
@@ -105,4 +105,6 @@ async function callOpenAIForDiagram(userText) {
105105
}
106106

107107
const PORT = process.env.PORT || 3001;
108-
http.listen(PORT);
108+
http.listen(PORT, () => {
109+
console.log(`Server is running on http://localhost:${PORT}`);
110+
});

frontend/app.js

Lines changed: 98 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,170 @@
11
require.config({ paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.28.1/min/vs' }});
22

33
require.onError = function (err) {
4-
const errorMessageDiv = document.getElementById("error-message");
5-
if (errorMessageDiv) {
6-
errorMessageDiv.textContent = 'Error: The code editor failed to load. Please check your internet connection and try refreshing the page. Details: ' + err;
4+
const errorMessageElement = document.getElementById("error-message");
5+
if (errorMessageElement) {
6+
errorMessageElement.textContent = 'Error: The code editor failed to load. Please check your internet connection and try refreshing the page. Details: ' + err;
77
}
88
console.error(err);
99
};
1010

11-
require(['vs/editor/editor.main'], function() {
12-
const loader = document.getElementById("loader");
13-
const errorMessageDiv = document.getElementById("error-message");
14-
const userInput = document.getElementById("user-input");
15-
const analyzeBtn = document.getElementById("analyze-btn");
11+
function initializeApp(monacoInstance) {
12+
// DOM Element Lookups
13+
const userInputTextArea = document.getElementById("user-input");
14+
const analyzeButton = document.getElementById("analyze-btn");
15+
const confirmButton = document.getElementById("confirm-btn");
16+
const reviewTextArea = document.getElementById("rephrased-text");
17+
const errorMessageElement = document.getElementById("error-message");
1618

17-
const step2Details = document.getElementById("step-2-details");
18-
const diagramDetails = document.getElementById("diagram-details");
19-
const step4Details = document.getElementById("step-4-details");
19+
const reviewSection = document.getElementById("review-section");
20+
const diagramSection = document.getElementById("diagram-section");
21+
const exportSection = document.getElementById("export-section");
2022

21-
const rephrasedText = document.getElementById("rephrased-text");
22-
const confirmBtn = document.getElementById("confirm-btn");
23-
24-
const exportJsonBtn = document.getElementById("export-json-btn");
25-
const exportPngBtn = document.getElementById("export-png-btn");
26-
const exportPdfBtn = document.getElementById("export-pdf-btn");
23+
const exportJsonButton = document.getElementById("export-json-btn");
24+
const exportPngButton = document.getElementById("export-png-btn");
25+
const exportPdfButton = document.getElementById("export-pdf-btn");
2726

2827
const promptButtons = document.querySelectorAll('.prompt-pill');
29-
promptButtons.forEach(button => {
30-
button.addEventListener('click', () => {
31-
userInput.value = button.dataset.prompt;
32-
// Clear step 2 and diagram when new prompt is selected
33-
clearStep2AndDiagram();
34-
});
35-
});
3628

37-
// Clear step 2 and diagram when user starts typing in step 1
29+
// State
3830
let previousInputValue = '';
39-
userInput.addEventListener('input', () => {
40-
const currentValue = userInput.value;
41-
// Clear when user starts typing new content (not just when emptying)
42-
if (currentValue !== previousInputValue && (step2Details.open || diagramDetails.open || step4Details.open)) {
43-
clearStep2AndDiagram();
44-
}
45-
previousInputValue = currentValue;
46-
});
47-
31+
let debounceTimer;
32+
33+
// Initializations
4834
const socket = io();
4935
const diagramEditor = new dhx.DiagramEditor("diagram-container", {
5036
type: "org",
5137
shapeType: "img-card"
5238
});
5339

54-
const jsonEditor = monaco.editor.create(document.getElementById('json-editor'), {
40+
const jsonEditor = monacoInstance.editor.create(document.getElementById('json-editor'), {
5541
value: '',
5642
language: 'json',
5743
theme: 'vs-dark',
5844
readOnly: false,
5945
automaticLayout: true
6046
});
6147

62-
let debounceTimer;
48+
// Functions
49+
function setButtonLoadingState(isLoading, button) {
50+
if (!button) return;
51+
52+
if (isLoading) {
53+
button.dataset.originalText = button.innerHTML;
54+
button.innerHTML = '💡 Thinking...';
55+
button.disabled = true;
56+
} else {
57+
if (button.dataset.originalText) {
58+
button.innerHTML = button.dataset.originalText;
59+
}
60+
button.disabled = false;
61+
}
62+
}
63+
64+
function displayError(message) {
65+
errorMessageElement.textContent = message;
66+
}
67+
68+
function resetUI() {
69+
reviewTextArea.value = '';
70+
diagramEditor.diagram.data.parse([]);
71+
jsonEditor.setValue('');
72+
73+
reviewSection.open = false;
74+
diagramSection.open = false;
75+
exportSection.open = false;
76+
77+
displayError('');
78+
}
79+
80+
// Event Listeners
81+
promptButtons.forEach(button => {
82+
button.addEventListener('click', () => {
83+
userInputTextArea.value = button.dataset.prompt;
84+
resetUI();
85+
});
86+
});
87+
88+
userInputTextArea.addEventListener('input', () => {
89+
const currentValue = userInputTextArea.value;
90+
if (currentValue !== previousInputValue && (reviewSection.open || diagramSection.open || exportSection.open)) {
91+
resetUI();
92+
}
93+
previousInputValue = currentValue;
94+
});
95+
6396
jsonEditor.onDidChangeModelContent(() => {
6497
clearTimeout(debounceTimer);
6598
debounceTimer = setTimeout(() => {
6699
try {
67100
const jsonData = JSON.parse(jsonEditor.getValue());
68101
diagramEditor.diagram.data.parse(jsonData);
69-
showError('');
102+
displayError('');
70103
} catch (e) {
71104
// It's okay if the JSON is temporarily invalid while typing
72105
}
73106
}, 500);
74107
});
75108

76-
analyzeBtn.addEventListener('click', () => {
77-
const text = userInput.value;
109+
analyzeButton.addEventListener('click', () => {
110+
const text = userInputTextArea.value;
78111
if (!text) {
79-
showError("Please enter a description.");
112+
displayError("Please enter a description.");
80113
return;
81114
}
82-
setLoading(true, analyzeBtn);
83-
clearStep2AndDiagram();
115+
setButtonLoadingState(true, analyzeButton);
116+
resetUI();
84117

85118
socket.emit('rephrase_text', { text }, (response) => {
86-
setLoading(false, analyzeBtn);
119+
setButtonLoadingState(false, analyzeButton);
87120
if (response.status === 'success') {
88-
rephrasedText.value = response.payload;
89-
step2Details.open = true;
90-
showError('');
121+
reviewTextArea.value = response.payload;
122+
reviewSection.open = true;
123+
displayError('');
91124
} else {
92-
showError("Analysis error: " + response.message);
125+
displayError("Analysis error: " + response.message);
93126
}
94127
});
95128
});
96129

97-
confirmBtn.addEventListener('click', () => {
98-
const verifiedText = rephrasedText.value;
130+
confirmButton.addEventListener('click', () => {
131+
const verifiedText = reviewTextArea.value;
99132
if (!verifiedText) {
100-
showError("Text for analysis cannot be empty.");
133+
displayError("Text for analysis cannot be empty.");
101134
return;
102135
}
103-
setLoading(true, confirmBtn);
136+
setButtonLoadingState(true, confirmButton);
104137

105138
socket.emit('generate_diagram', { text: verifiedText }, (response) => {
106-
setLoading(false, confirmBtn);
139+
setButtonLoadingState(false, confirmButton);
107140
if (response.status === 'success') {
108141
const data = response.payload;
109142
jsonEditor.setValue(JSON.stringify(data, null, 2));
110143
diagramEditor.diagram.data.parse(data);
111144

112-
diagramDetails.open = true;
113-
step4Details.open = true;
114-
showError('');
145+
diagramSection.open = true;
146+
exportSection.open = true;
147+
displayError('');
115148

116149
setTimeout(() => {
117-
step2Details.scrollIntoView({ behavior: "smooth", block: "start" });
150+
reviewSection.scrollIntoView({ behavior: "smooth", block: "start" });
118151
}, 100);
119152

120153
} else {
121-
showError("Generation error: " + response.message);
154+
displayError("Generation error: " + response.message);
122155
}
123156
});
124157
});
125158

126-
exportPngBtn.addEventListener('click', () => {
159+
exportPngButton.addEventListener('click', () => {
127160
diagramEditor.diagram.export.png();
128161
});
129162

130-
exportPdfBtn.addEventListener('click', () => {
163+
exportPdfButton.addEventListener('click', () => {
131164
diagramEditor.diagram.export.pdf();
132165
});
133166

134-
exportJsonBtn.addEventListener('click', () => {
167+
exportJsonButton.addEventListener('click', () => {
135168
const jsonData = diagramEditor.diagram.data.serialize();
136169
const blob = new Blob([JSON.stringify(jsonData, null, 2)], { type: 'application/json' });
137170
const url = URL.createObjectURL(blob);
@@ -143,37 +176,9 @@ require(['vs/editor/editor.main'], function() {
143176
document.body.removeChild(a);
144177
URL.revokeObjectURL(url);
145178
});
179+
}
146180

147-
function setLoading(isLoading, button) {
148-
if (isLoading) {
149-
loader.classList.remove("hidden");
150-
if (button) button.disabled = true;
151-
} else {
152-
loader.classList.add("hidden");
153-
if (button) button.disabled = false;
154-
}
155-
}
156-
157-
function showError(message) {
158-
errorMessageDiv.textContent = message;
159-
}
160-
161-
function clearStep2AndDiagram() {
162-
// Clear rephrased text (step 2)
163-
rephrasedText.value = '';
164-
165-
// Clear diagram
166-
diagramEditor.diagram.data.parse([]);
167-
168-
// Clear JSON editor
169-
jsonEditor.setValue('');
170-
171-
// Close all detail sections
172-
step2Details.open = false;
173-
diagramDetails.open = false;
174-
step4Details.open = false;
175-
176-
// Clear error messages
177-
showError('');
178-
}
179-
});
181+
// Entry point: Load the Monaco editor and then initialize the application.
182+
require(['vs/editor/editor.main'], function(monaco) {
183+
initializeApp(monaco);
184+
});

0 commit comments

Comments
 (0)