owenkaplinsky commited on
Commit
2d05ba7
·
1 Parent(s): 867b451

Use a singular port

Browse files
project/__pycache__/chat.cpython-311.pyc ADDED
Binary file (40.1 kB). View file
 
project/__pycache__/test.cpython-311.pyc ADDED
Binary file (13.5 kB). View file
 
project/chat.py CHANGED
@@ -93,7 +93,7 @@ def execute_mcp(mcp_call):
93
  # Now, retrieve the real generated Python code from test.py
94
  blockly_code = ""
95
  try:
96
- resp = requests.get("http://localhost:7860/get_latest_code")
97
  if resp.ok:
98
  blockly_code = resp.json().get("code", "")
99
  except Exception as e:
@@ -904,10 +904,11 @@ You will be given the current variables that are in the workspace. Like the bloc
904
 
905
  return demo
906
 
907
- # Mount Gradio with FastAPI
908
- demo = create_gradio_interface()
909
- app = gr.mount_gradio_app(app, demo, path="/")
 
910
 
911
  if __name__ == "__main__":
912
- print("[BOOT] Running Gradio+FastAPI Chat on http://127.0.0.1:7861")
913
- uvicorn.run(app, host="0.0.0.0", port=7861)
 
93
  # Now, retrieve the real generated Python code from test.py
94
  blockly_code = ""
95
  try:
96
+ resp = requests.get(f"http://127.0.0.1:{os.getenv('PORT', 8080)}/get_latest_code")
97
  if resp.ok:
98
  blockly_code = resp.json().get("code", "")
99
  except Exception as e:
 
904
 
905
  return demo
906
 
907
+
908
+ def get_chat_gradio_interface():
909
+ return create_gradio_interface()
910
+
911
 
912
  if __name__ == "__main__":
913
+ demo = create_gradio_interface()
914
+ app = gr.mount_gradio_app(app, demo, path="/")
project/dist/bundle.js ADDED
The diff for this file is too large to render. See raw diff
 
project/dist/bundle.js.LICENSE.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ /**
2
+ * @license
3
+ * Copyright 2019 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
project/dist/bundle.js.map ADDED
The diff for this file is too large to render. See raw diff
 
project/dist/index.html ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html><html><head><meta charset="utf-8"/><title>Blockly MCP Builder</title><script defer="defer" src="bundle.js"></script></head><body><div id="topBar"><div id="titleSection"><h1>Blockly MCP Builder</h1></div><div id="divider"></div><div id="menuSection"><div class="menuGroup"><button class="menuButton">File</button><div class="dropdown"><a href="#" id="newButton" class="dropdownItem" data-action="new">New</a> <a href="#" id="loadButton" class="dropdownItem" data-action="open">Open</a> <a href="#" id="saveButton" class="dropdownItem" data-action="download">Download Project</a> <a href="#" id="downloadCodeButton" class="dropdownItem" data-action="downloadCode">Download Code</a> <a href="#" id="settingsButton" class="dropdownItem" data-action="downloadCode">API Key</a></div></div><div class="menuGroup"><button class="menuButton">Edit</button><div class="dropdown"><a href="#" id="undoButton" class="dropdownItem" data-action="undo">Undo</a> <a href="#" id="redoButton" class="dropdownItem" data-action="redo">Redo</a> <a href="#" id="cleanWorkspace" class="dropdownItem" data-action="cleanup">Clean up</a></div></div><div class="menuGroup"><button class="menuButton">Examples</button><div class="dropdown"><a href="#" id="weatherButton" class="dropdownItem" data-action="undo">Weather API</a> <a href="#" id="factButton" class="dropdownItem" data-action="undo">Fact Checker</a></div></div></div><div id="githubLink"><a href="https://github.com/owenkaplinsky/mcp-blockly" target="_blank" rel="noopener noreferrer"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v 3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg></a></div></div><div id="pageContainer"><div id="outputPane"><div id="tabBar"><div class="tab active" data-tab="development">Development</div><div class="tab" data-tab="aichat">AI Chat</div></div><div id="developmentTab" class="tabContent active"><div id="chatContainer"><iframe src="/gradio-test" style="width: 100%; height: 100%; border: none;"></iframe></div><div class="verticalResizer"></div><pre id="generatedCode"><code></code></pre></div><div id="aichatTab" class="tabContent"><div id="gradioContainer"><iframe src="/gradio-chat" style="width: 100%; height: 100%; border: none;"></iframe></div><pre id="aichatCode" style="position: absolute; left: -9999px; width: 1px; height: 1px;"><code></code></pre></div></div><div class="resizer"></div><div id="blocklyDiv"></div></div><script>// Tab switching functionality
2
+ const tabs = document.querySelectorAll('.tab');
3
+ const tabContents = document.querySelectorAll('.tabContent');
4
+
5
+ tabs.forEach(tab => {
6
+ tab.addEventListener('click', () => {
7
+ const tabName = tab.getAttribute('data-tab');
8
+
9
+ // Remove active class from all tabs and contents
10
+ tabs.forEach(t => t.classList.remove('active'));
11
+ tabContents.forEach(content => content.classList.remove('active'));
12
+
13
+ // Add active class to clicked tab and corresponding content
14
+ tab.classList.add('active');
15
+ document.getElementById(tabName + 'Tab').classList.add('active');
16
+ });
17
+ });
18
+
19
+ // Horizontal resizer (output pane vs blockly)
20
+ const resizer = document.querySelector('.resizer');
21
+ const outputPane = document.getElementById('outputPane');
22
+ const pageContainer = document.getElementById('pageContainer');
23
+
24
+ let startX = 0;
25
+ let startWidth = 0;
26
+
27
+ function onPointerMove(e) {
28
+ const containerRect = pageContainer.getBoundingClientRect();
29
+ const containerWidth = containerRect.width;
30
+
31
+ const dx = e.clientX - startX;
32
+ let newWidthPx = startWidth + dx;
33
+
34
+ const minWidth = containerWidth * 0.2;
35
+ const maxWidth = containerWidth * 0.59;
36
+ newWidthPx = Math.max(minWidth, Math.min(maxWidth, newWidthPx));
37
+
38
+ const newPercent = (newWidthPx / containerWidth) * 100;
39
+ outputPane.style.flex = `0 0 ${newPercent}%`;
40
+ }
41
+
42
+ function onPointerUp() {
43
+ resizer.releasePointerCapture(activePointerId);
44
+ resizer.removeEventListener('pointermove', onPointerMove);
45
+ resizer.removeEventListener('pointerup', onPointerUp);
46
+ resizer.classList.remove('active');
47
+ document.body.style.cursor = '';
48
+ document.body.style.userSelect = '';
49
+ }
50
+
51
+ let activePointerId = null;
52
+
53
+ resizer.addEventListener('pointerdown', (e) => {
54
+ const rect = outputPane.getBoundingClientRect();
55
+ startX = e.clientX;
56
+ startWidth = rect.width;
57
+ activePointerId = e.pointerId;
58
+
59
+ resizer.classList.add('active');
60
+ document.body.style.cursor = 'col-resize';
61
+ document.body.style.userSelect = 'none';
62
+
63
+ resizer.setPointerCapture(activePointerId);
64
+ resizer.addEventListener('pointermove', onPointerMove);
65
+ resizer.addEventListener('pointerup', onPointerUp);
66
+ });
67
+
68
+ // Vertical resizer (gradio vs code)
69
+ const verticalResizer = document.querySelector('.verticalResizer');
70
+ const chatContainer = document.getElementById('chatContainer');
71
+ const generatedCode = document.getElementById('generatedCode');
72
+
73
+ let startY = 0;
74
+ let startHeight = 0;
75
+ let activePointerId2 = null;
76
+
77
+ function onVerticalPointerMove(e) {
78
+ const outputPaneRect = outputPane.getBoundingClientRect();
79
+ const outputPaneHeight = outputPaneRect.height;
80
+
81
+ const dy = e.clientY - startY;
82
+ let newHeightPx = startHeight + dy;
83
+
84
+ const minHeight = outputPaneHeight * 0.4;
85
+ const maxHeight = outputPaneHeight * 0.78;
86
+ newHeightPx = Math.max(minHeight, Math.min(maxHeight, newHeightPx));
87
+
88
+ const newPercent = (newHeightPx / outputPaneHeight) * 100;
89
+ chatContainer.style.flex = `0 0 ${newPercent}%`;
90
+ }
91
+
92
+ function onVerticalPointerUp() {
93
+ verticalResizer.releasePointerCapture(activePointerId2);
94
+ verticalResizer.removeEventListener('pointermove', onVerticalPointerMove);
95
+ verticalResizer.removeEventListener('pointerup', onVerticalPointerUp);
96
+ verticalResizer.classList.remove('active');
97
+ document.body.style.cursor = '';
98
+ document.body.style.userSelect = '';
99
+ }
100
+
101
+ verticalResizer.addEventListener('pointerdown', (e) => {
102
+ const rect = chatContainer.getBoundingClientRect();
103
+ startY = e.clientY;
104
+ startHeight = rect.height;
105
+ activePointerId2 = e.pointerId;
106
+
107
+ verticalResizer.classList.add('active');
108
+ document.body.style.cursor = 'row-resize';
109
+ document.body.style.userSelect = 'none';
110
+
111
+ verticalResizer.setPointerCapture(activePointerId2);
112
+ verticalResizer.addEventListener('pointermove', onVerticalPointerMove);
113
+ verticalResizer.addEventListener('pointerup', onVerticalPointerUp);
114
+ });</script><div id="apiKeyModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 9999; align-items: center; justify-content: center;"><div style="background: white; padding: 30px; border-radius: 10px; width: 90%; max-width: 500px; box-shadow: 0 10px 30px rgba(0,0,0,0.2);"><h2 style="margin-top: 0; margin-bottom: 20px; color: #333;">Settings</h2><label for="apiKeyInput" style="display: block; margin-bottom: 10px; color: #666; font-size: 14px;">OpenAI API Key:</label> <input type="password" id="apiKeyInput" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-size: 14px; box-sizing: border-box;" placeholder="sk-..."><p style="margin-top: 10px; color: #999; font-size: 12px;">Your API key will be stored securely for this session.</p><div style="margin-top: 20px; display: flex; justify-content: flex-end; gap: 10px;"><button id="cancelApiKey" style="padding: 10px 20px; background: #e5e7eb; border: none; border-radius: 5px; cursor: pointer; font-size: 14px;">Cancel</button> <button id="saveApiKey" style="padding: 10px 20px; background: #6366f1; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 14px;">Save</button></div></div></div></body></html>
project/package.json CHANGED
@@ -5,9 +5,8 @@
5
  "main": "index.js",
6
  "private": true,
7
  "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1",
9
  "build": "webpack --mode production",
10
- "start": "concurrently \"python test.py\" \"python chat.py\" \"webpack serve --open --mode development\""
11
  },
12
  "keywords": [
13
  "blockly"
 
5
  "main": "index.js",
6
  "private": true,
7
  "scripts": {
 
8
  "build": "webpack --mode production",
9
+ "start": "npm run build && python unified_server.py"
10
  },
11
  "keywords": [
12
  "blockly"
project/src/index.html CHANGED
@@ -59,14 +59,14 @@
59
  </div>
60
  <div id="developmentTab" class="tabContent active">
61
  <div id="chatContainer">
62
- <iframe src="http://127.0.0.1:7860" style="width: 100%; height: 100%; border: none;"></iframe>
63
  </div>
64
  <div class="verticalResizer"></div>
65
  <pre id="generatedCode"><code></code></pre>
66
  </div>
67
  <div id="aichatTab" class="tabContent">
68
  <div id="gradioContainer">
69
- <iframe src="http://127.0.0.1:7861" style="width: 100%; height: 100%; border: none;"></iframe>
70
  </div>
71
  <pre id="aichatCode" style="position: absolute; left: -9999px; width: 1px; height: 1px;"><code></code></pre>
72
  </div>
 
59
  </div>
60
  <div id="developmentTab" class="tabContent active">
61
  <div id="chatContainer">
62
+ <iframe src="/gradio-test" style="width: 100%; height: 100%; border: none;"></iframe>
63
  </div>
64
  <div class="verticalResizer"></div>
65
  <pre id="generatedCode"><code></code></pre>
66
  </div>
67
  <div id="aichatTab" class="tabContent">
68
  <div id="gradioContainer">
69
+ <iframe src="/gradio-chat" style="width: 100%; height: 100%; border: none;"></iframe>
70
  </div>
71
  <pre id="aichatCode" style="position: absolute; left: -9999px; width: 1px; height: 1px;"><code></code></pre>
72
  </div>
project/src/index.js CHANGED
@@ -160,7 +160,7 @@ settingsButton.addEventListener("click", () => {
160
  apiKeyModal.style.display = 'flex';
161
 
162
  // Load current API key from backend
163
- fetch("http://127.0.0.1:7860/get_api_key", {
164
  method: "GET",
165
  })
166
  .then(response => response.json())
@@ -183,12 +183,12 @@ saveApiKeyButton.addEventListener("click", () => {
183
 
184
  // Save API key to both backend servers (test.py and chat.py)
185
  Promise.all([
186
- fetch("http://127.0.0.1:7860/set_api_key", {
187
  method: "POST",
188
  headers: { "Content-Type": "application/json" },
189
  body: JSON.stringify({ api_key: apiKey }),
190
  }),
191
- fetch("http://127.0.0.1:7861/set_api_key_chat", {
192
  method: "POST",
193
  headers: { "Content-Type": "application/json" },
194
  body: JSON.stringify({ api_key: apiKey }),
@@ -247,7 +247,7 @@ cleanWorkspace.addEventListener("click", () => {
247
 
248
  // Set up SSE connection for deletion requests
249
  const setupDeletionStream = () => {
250
- const eventSource = new EventSource('http://127.0.0.1:7861/delete_stream');
251
  const processedRequests = new Set(); // Track processed deletion requests
252
 
253
  eventSource.onmessage = (event) => {
@@ -300,7 +300,7 @@ const setupDeletionStream = () => {
300
 
301
  // Send result back to backend immediately
302
  console.log('[SSE] Sending deletion result:', { block_id: data.block_id, success, error });
303
- fetch('http://127.0.0.1:7861/deletion_result', {
304
  method: 'POST',
305
  headers: { 'Content-Type': 'application/json' },
306
  body: JSON.stringify({
@@ -338,7 +338,7 @@ setupDeletionStream();
338
 
339
  // Set up SSE connection for creation requests
340
  const setupCreationStream = () => {
341
- const eventSource = new EventSource('http://127.0.0.1:7861/create_stream');
342
  const processedRequests = new Set(); // Track processed creation requests
343
 
344
  eventSource.onmessage = (event) => {
@@ -712,7 +712,7 @@ const setupCreationStream = () => {
712
  block_id: blockId
713
  });
714
 
715
- fetch('http://127.0.0.1:7861/creation_result', {
716
  method: 'POST',
717
  headers: { 'Content-Type': 'application/json' },
718
  body: JSON.stringify({
@@ -750,7 +750,7 @@ const setupCreationStream = () => {
750
  setupCreationStream();
751
 
752
  const setupVariableStream = () => {
753
- const eventSource = new EventSource('http://127.0.0.1:7861/variable_stream');
754
  const processedRequests = new Set(); // Track processed variable requests
755
 
756
  eventSource.onmessage = (event) => {
@@ -806,7 +806,7 @@ const setupVariableStream = () => {
806
  variable_id: variableId
807
  });
808
 
809
- fetch('http://127.0.0.1:7861/variable_result', {
810
  method: 'POST',
811
  headers: { 'Content-Type': 'application/json' },
812
  body: JSON.stringify({
@@ -928,7 +928,7 @@ const updateCode = () => {
928
  }
929
 
930
  // Send generated Python code to backend
931
- fetch("http://127.0.0.1:7860/update_code", {
932
  method: "POST",
933
  headers: { "Content-Type": "application/json" },
934
  body: JSON.stringify({ code }),
@@ -953,7 +953,7 @@ let globalVarString = '';
953
  // Function to check if chat backend is available
954
  const checkChatBackend = async () => {
955
  try {
956
- const response = await fetch("http://127.0.0.1:7861/update_chat", {
957
  method: "POST",
958
  headers: { "Content-Type": "application/json" },
959
  body: JSON.stringify({
@@ -986,7 +986,7 @@ const processChatUpdateQueue = () => {
986
  // Send chat update with retry logic
987
  const sendChatUpdate = async (chatCode, retryCount = 0) => {
988
  try {
989
- const response = await fetch("http://127.0.0.1:7861/update_chat", {
990
  method: "POST",
991
  headers: { "Content-Type": "application/json" },
992
  body: JSON.stringify({
 
160
  apiKeyModal.style.display = 'flex';
161
 
162
  // Load current API key from backend
163
+ fetch("/get_api_key", {
164
  method: "GET",
165
  })
166
  .then(response => response.json())
 
183
 
184
  // Save API key to both backend servers (test.py and chat.py)
185
  Promise.all([
186
+ fetch("/set_api_key", {
187
  method: "POST",
188
  headers: { "Content-Type": "application/json" },
189
  body: JSON.stringify({ api_key: apiKey }),
190
  }),
191
+ fetch("/set_api_key_chat", {
192
  method: "POST",
193
  headers: { "Content-Type": "application/json" },
194
  body: JSON.stringify({ api_key: apiKey }),
 
247
 
248
  // Set up SSE connection for deletion requests
249
  const setupDeletionStream = () => {
250
+ const eventSource = new EventSource('/delete_stream');
251
  const processedRequests = new Set(); // Track processed deletion requests
252
 
253
  eventSource.onmessage = (event) => {
 
300
 
301
  // Send result back to backend immediately
302
  console.log('[SSE] Sending deletion result:', { block_id: data.block_id, success, error });
303
+ fetch('/deletion_result', {
304
  method: 'POST',
305
  headers: { 'Content-Type': 'application/json' },
306
  body: JSON.stringify({
 
338
 
339
  // Set up SSE connection for creation requests
340
  const setupCreationStream = () => {
341
+ const eventSource = new EventSource('/create_stream');
342
  const processedRequests = new Set(); // Track processed creation requests
343
 
344
  eventSource.onmessage = (event) => {
 
712
  block_id: blockId
713
  });
714
 
715
+ fetch('/creation_result', {
716
  method: 'POST',
717
  headers: { 'Content-Type': 'application/json' },
718
  body: JSON.stringify({
 
750
  setupCreationStream();
751
 
752
  const setupVariableStream = () => {
753
+ const eventSource = new EventSource('/variable_stream');
754
  const processedRequests = new Set(); // Track processed variable requests
755
 
756
  eventSource.onmessage = (event) => {
 
806
  variable_id: variableId
807
  });
808
 
809
+ fetch('/variable_result', {
810
  method: 'POST',
811
  headers: { 'Content-Type': 'application/json' },
812
  body: JSON.stringify({
 
928
  }
929
 
930
  // Send generated Python code to backend
931
+ fetch("/update_code", {
932
  method: "POST",
933
  headers: { "Content-Type": "application/json" },
934
  body: JSON.stringify({ code }),
 
953
  // Function to check if chat backend is available
954
  const checkChatBackend = async () => {
955
  try {
956
+ const response = await fetch("/update_chat", {
957
  method: "POST",
958
  headers: { "Content-Type": "application/json" },
959
  body: JSON.stringify({
 
986
  // Send chat update with retry logic
987
  const sendChatUpdate = async (chatCode, retryCount = 0) => {
988
  try {
989
+ const response = await fetch("/update_chat", {
990
  method: "POST",
991
  headers: { "Content-Type": "application/json" },
992
  body: JSON.stringify({
project/test.py CHANGED
@@ -293,15 +293,17 @@ def build_interface():
293
  submit_btn.click(
294
  process_input,
295
  inputs=input_fields,
296
- outputs=output_fields
 
297
  )
298
 
299
  return demo
300
 
301
 
302
- demo = build_interface()
303
- app = gr.mount_gradio_app(app, demo, path="/")
 
304
 
305
  if __name__ == "__main__":
306
- print("[BOOT] Running Gradio+FastAPI combo on http://127.0.0.1:7860")
307
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
293
  submit_btn.click(
294
  process_input,
295
  inputs=input_fields,
296
+ outputs=output_fields,
297
+ queue=False
298
  )
299
 
300
  return demo
301
 
302
 
303
+ def get_gradio_interface():
304
+ return build_interface()
305
+
306
 
307
  if __name__ == "__main__":
308
+ demo = build_interface()
309
+ app = gr.mount_gradio_app(app, demo, path="/")
project/unified_server.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, Request
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.staticfiles import StaticFiles
4
+ import gradio as gr
5
+ import uvicorn
6
+ import os
7
+ import sys
8
+
9
+ # Ensure local modules are importable
10
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
11
+ import test
12
+ import chat
13
+
14
+ app = FastAPI()
15
+
16
+ app.add_middleware(
17
+ CORSMiddleware,
18
+ allow_origins=["*"],
19
+ allow_credentials=True,
20
+ allow_methods=["*"],
21
+ allow_headers=["*"],
22
+ )
23
+
24
+ # -------------------------------------------------------------------
25
+ # Full API Forwarding Layer for chat.py and test.py
26
+ # -------------------------------------------------------------------
27
+
28
+ # === chat.py API endpoints ===
29
+ @app.post("/update_chat")
30
+ async def update_chat_route(request: Request):
31
+ return await chat.update_chat(request)
32
+
33
+ @app.post("/set_api_key_chat")
34
+ async def set_api_key_chat_route(request: Request):
35
+ return await chat.set_api_key_chat(request)
36
+
37
+ @app.get("/create_stream")
38
+ async def create_stream_route():
39
+ return await chat.create_stream()
40
+
41
+ @app.post("/creation_result")
42
+ async def creation_result_route(request: Request):
43
+ return await chat.creation_result(request)
44
+
45
+ @app.get("/delete_stream")
46
+ async def delete_stream_route():
47
+ return await chat.delete_stream()
48
+
49
+ @app.post("/deletion_result")
50
+ async def deletion_result_route(request: Request):
51
+ return await chat.deletion_result(request)
52
+
53
+ @app.get("/variable_stream")
54
+ async def variable_stream_route():
55
+ return await chat.variable_stream()
56
+
57
+ @app.post("/variable_result")
58
+ async def variable_result_route(request: Request):
59
+ return await chat.variable_result(request)
60
+
61
+
62
+ # === test.py API endpoints ===
63
+ @app.post("/update_code")
64
+ async def update_code_route(request: Request):
65
+ return await test.update_code(request)
66
+
67
+ @app.get("/get_latest_code")
68
+ async def get_latest_code_route():
69
+ return await test.get_latest_code()
70
+
71
+ @app.get("/get_api_key")
72
+ async def get_api_key_route():
73
+ return await test.get_api_key_endpoint()
74
+
75
+ @app.post("/set_api_key")
76
+ async def set_api_key_route(request: Request):
77
+ return await test.set_api_key_endpoint(request)
78
+
79
+ # Serve built frontend WITHOUT shadowing Gradio paths
80
+ from fastapi.responses import FileResponse
81
+
82
+ frontend_dir = os.path.join(os.path.dirname(__file__), "dist")
83
+ if not os.path.exists(frontend_dir):
84
+ os.makedirs(frontend_dir)
85
+
86
+ @app.get("/")
87
+ def serve_index():
88
+ return FileResponse(os.path.join(frontend_dir, "index.html"))
89
+
90
+ @app.get("/bundle.js")
91
+ def serve_bundle():
92
+ return FileResponse(os.path.join(frontend_dir, "bundle.js"))
93
+
94
+ # Optionally serve other built assets if needed
95
+ app.mount("/assets", StaticFiles(directory=frontend_dir), name="assets")
96
+
97
+ # Mount both Gradio interfaces
98
+ test_demo = test.get_gradio_interface()
99
+ chat_demo = chat.get_chat_gradio_interface()
100
+
101
+ # Mount the Gradio apps directly
102
+ app = gr.mount_gradio_app(app, test_demo, path="/gradio-test")
103
+ app = gr.mount_gradio_app(app, chat_demo, path="/gradio-chat")
104
+
105
+ print("new /gradio-test")
106
+ print("new /gradio-chat")
107
+
108
+ if __name__ == "__main__":
109
+ port = int(os.getenv("PORT", 8080))
110
+ print(f"[UNIFIED] running on http://127.0.0.1:{port}")
111
+ print(f"- /gradio-test")
112
+ print(f"- /gradio-chat")
113
+ uvicorn.run(app, host="0.0.0.0", port=port)
project/webpack.config.js CHANGED
@@ -27,15 +27,6 @@ module.exports = {
27
  template: './src/index.html',
28
  }),
29
  ],
30
- devServer: {
31
- static: {
32
- directory: path.join(__dirname, 'public'),
33
- },
34
- compress: true,
35
- port: 8081,
36
- hot: true,
37
- open: true,
38
- },
39
  resolve: {
40
  extensions: ['.js', '.json', '.css'],
41
  },
 
27
  template: './src/index.html',
28
  }),
29
  ],
 
 
 
 
 
 
 
 
 
30
  resolve: {
31
  extensions: ['.js', '.json', '.css'],
32
  },