auto-coder-web 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- auto_coder_web/__init__.py +0 -0
- auto_coder_web/auto_coder_runner.py +694 -0
- auto_coder_web/file_group.py +69 -0
- auto_coder_web/file_manager.py +114 -0
- auto_coder_web/hello.py +36 -0
- auto_coder_web/json_file_storage.py +44 -0
- auto_coder_web/proxy.py +532 -0
- auto_coder_web/terminal.py +259 -0
- auto_coder_web/version.py +1 -0
- auto_coder_web/web/asset-manifest.json +15 -0
- auto_coder_web/web/favicon.ico +0 -0
- auto_coder_web/web/index.html +1 -0
- auto_coder_web/web/logo192.png +0 -0
- auto_coder_web/web/logo512.png +0 -0
- auto_coder_web/web/manifest.json +25 -0
- auto_coder_web/web/robots.txt +3 -0
- auto_coder_web/web/static/css/main.0441fea8.css +6 -0
- auto_coder_web/web/static/css/main.0441fea8.css.map +1 -0
- auto_coder_web/web/static/js/453.8ab44547.chunk.js +2 -0
- auto_coder_web/web/static/js/453.8ab44547.chunk.js.map +1 -0
- auto_coder_web/web/static/js/main.9cc516f4.js +3 -0
- auto_coder_web/web/static/js/main.9cc516f4.js.LICENSE.txt +119 -0
- auto_coder_web/web/static/js/main.9cc516f4.js.map +1 -0
- auto_coder_web-0.1.0.dist-info/METADATA +34 -0
- auto_coder_web-0.1.0.dist-info/RECORD +28 -0
- auto_coder_web-0.1.0.dist-info/WHEEL +5 -0
- auto_coder_web-0.1.0.dist-info/entry_points.txt +2 -0
- auto_coder_web-0.1.0.dist-info/top_level.txt +1 -0
auto_coder_web/proxy.py
ADDED
@@ -0,0 +1,532 @@
|
|
1
|
+
from fastapi import FastAPI, Request, HTTPException, Response, Query
|
2
|
+
from fastapi.responses import HTMLResponse, JSONResponse
|
3
|
+
from fastapi import WebSocket
|
4
|
+
from fastapi.middleware.cors import CORSMiddleware
|
5
|
+
from fastapi.staticfiles import StaticFiles
|
6
|
+
import uvicorn
|
7
|
+
import httpx
|
8
|
+
import uuid
|
9
|
+
from typing import Optional, Dict, List
|
10
|
+
import os
|
11
|
+
import argparse
|
12
|
+
import aiofiles
|
13
|
+
import pkg_resources
|
14
|
+
from .file_group import FileGroupManager
|
15
|
+
from .file_manager import get_directory_tree
|
16
|
+
from .auto_coder_runner import AutoCoderRunner
|
17
|
+
|
18
|
+
from rich.console import Console
|
19
|
+
from prompt_toolkit.shortcuts import radiolist_dialog
|
20
|
+
from prompt_toolkit.formatted_text import HTML
|
21
|
+
import subprocess
|
22
|
+
from prompt_toolkit import prompt
|
23
|
+
from pydantic import BaseModel
|
24
|
+
from autocoder.utils.log_capture import LogCapture
|
25
|
+
from typing import Optional, Dict, List, Any
|
26
|
+
from .terminal import terminal_manager
|
27
|
+
|
28
|
+
|
29
|
+
class EventGetRequest(BaseModel):
|
30
|
+
request_id: str
|
31
|
+
|
32
|
+
|
33
|
+
class EventResponseRequest(BaseModel):
|
34
|
+
request_id: str
|
35
|
+
event: Dict[str, str]
|
36
|
+
response: str
|
37
|
+
|
38
|
+
|
39
|
+
class CompletionItem(BaseModel):
|
40
|
+
name: str
|
41
|
+
path: str
|
42
|
+
display: str
|
43
|
+
location: Optional[str] = None
|
44
|
+
|
45
|
+
|
46
|
+
class CompletionResponse(BaseModel):
|
47
|
+
completions: List[CompletionItem]
|
48
|
+
|
49
|
+
|
50
|
+
def check_environment():
|
51
|
+
"""Check and initialize the required environment"""
|
52
|
+
console = Console()
|
53
|
+
console.print("\n[blue]Initializing the environment...[/blue]")
|
54
|
+
|
55
|
+
def check_project():
|
56
|
+
"""Check if the current directory is initialized as an auto-coder project"""
|
57
|
+
def print_status(message, status):
|
58
|
+
if status == "success":
|
59
|
+
console.print(f"✓ {message}", style="green")
|
60
|
+
elif status == "warning":
|
61
|
+
console.print(f"! {message}", style="yellow")
|
62
|
+
elif status == "error":
|
63
|
+
console.print(f"✗ {message}", style="red")
|
64
|
+
else:
|
65
|
+
console.print(f" {message}")
|
66
|
+
|
67
|
+
first_time = False
|
68
|
+
if not os.path.exists("actions") or not os.path.exists(".auto-coder"):
|
69
|
+
first_time = True
|
70
|
+
print_status("Project not initialized", "warning")
|
71
|
+
init_choice = input(
|
72
|
+
" Do you want to initialize the project? (y/n): ").strip().lower()
|
73
|
+
if init_choice == "y":
|
74
|
+
try:
|
75
|
+
if not os.path.exists("actions"):
|
76
|
+
os.makedirs("actions", exist_ok=True)
|
77
|
+
print_status("Created actions directory", "success")
|
78
|
+
|
79
|
+
if not os.path.exists(".auto-coder"):
|
80
|
+
os.makedirs(".auto-coder", exist_ok=True)
|
81
|
+
print_status(
|
82
|
+
"Created .auto-coder directory", "success")
|
83
|
+
|
84
|
+
subprocess.run(
|
85
|
+
["auto-coder", "init", "--source_dir", "."], check=True)
|
86
|
+
print_status("Project initialized successfully", "success")
|
87
|
+
except subprocess.CalledProcessError:
|
88
|
+
print_status("Failed to initialize project", "error")
|
89
|
+
print_status(
|
90
|
+
"Please try to initialize manually: auto-coder init --source_dir .", "warning")
|
91
|
+
return False
|
92
|
+
else:
|
93
|
+
print_status("Exiting due to no initialization", "warning")
|
94
|
+
return False
|
95
|
+
|
96
|
+
print_status("Project initialization check complete", "success")
|
97
|
+
return True
|
98
|
+
|
99
|
+
if not check_project():
|
100
|
+
return False
|
101
|
+
|
102
|
+
def print_status(message, status):
|
103
|
+
if status == "success":
|
104
|
+
console.print(f"✓ {message}", style="green")
|
105
|
+
elif status == "warning":
|
106
|
+
console.print(f"! {message}", style="yellow")
|
107
|
+
elif status == "error":
|
108
|
+
console.print(f"✗ {message}", style="red")
|
109
|
+
else:
|
110
|
+
console.print(f" {message}")
|
111
|
+
|
112
|
+
# Check if Ray is running
|
113
|
+
print_status("Checking Ray", "")
|
114
|
+
ray_status = subprocess.run(
|
115
|
+
["ray", "status"], capture_output=True, text=True)
|
116
|
+
if ray_status.returncode != 0:
|
117
|
+
print_status("Ray is not running", "warning")
|
118
|
+
try:
|
119
|
+
subprocess.run(["ray", "start", "--head"], check=True)
|
120
|
+
print_status("Ray started successfully", "success")
|
121
|
+
except subprocess.CalledProcessError:
|
122
|
+
print_status("Failed to start Ray", "error")
|
123
|
+
return False
|
124
|
+
|
125
|
+
# Check if deepseek_chat model is available
|
126
|
+
print_status("Checking deepseek_chat model", "")
|
127
|
+
try:
|
128
|
+
result = subprocess.run(
|
129
|
+
["easy-byzerllm", "chat", "deepseek_chat", "你好"],
|
130
|
+
capture_output=True,
|
131
|
+
text=True,
|
132
|
+
timeout=30,
|
133
|
+
)
|
134
|
+
if result.returncode == 0:
|
135
|
+
print_status("deepseek_chat model is available", "success")
|
136
|
+
print_status("Environment check complete", "success")
|
137
|
+
return True
|
138
|
+
except subprocess.TimeoutExpired:
|
139
|
+
print_status("Model check timeout", "error")
|
140
|
+
except subprocess.CalledProcessError:
|
141
|
+
print_status("Model check error", "error")
|
142
|
+
except Exception as e:
|
143
|
+
print_status(f"Unexpected error: {str(e)}", "error")
|
144
|
+
|
145
|
+
print_status("deepseek_chat model is not available", "warning")
|
146
|
+
|
147
|
+
# If deepseek_chat is not available, prompt user to choose a provider
|
148
|
+
choice = radiolist_dialog(
|
149
|
+
title="Select Provider",
|
150
|
+
text="Please select a provider for deepseek_chat model:",
|
151
|
+
values=[
|
152
|
+
("1", "硅基流动(https://siliconflow.cn)"),
|
153
|
+
("2", "Deepseek官方(https://www.deepseek.com/)"),
|
154
|
+
],
|
155
|
+
).run()
|
156
|
+
|
157
|
+
if choice is None:
|
158
|
+
print_status("No provider selected", "error")
|
159
|
+
return False
|
160
|
+
|
161
|
+
api_key = prompt(HTML("<b>Please enter your API key: </b>"))
|
162
|
+
|
163
|
+
if choice == "1":
|
164
|
+
print_status("Deploying model with 硅基流动", "")
|
165
|
+
deploy_cmd = [
|
166
|
+
"easy-byzerllm",
|
167
|
+
"deploy",
|
168
|
+
"deepseek-ai/deepseek-v2-chat",
|
169
|
+
"--token",
|
170
|
+
api_key,
|
171
|
+
"--alias",
|
172
|
+
"deepseek_chat",
|
173
|
+
]
|
174
|
+
else:
|
175
|
+
print_status("Deploying model with Deepseek官方", "")
|
176
|
+
deploy_cmd = [
|
177
|
+
"byzerllm",
|
178
|
+
"deploy",
|
179
|
+
"--pretrained_model_type",
|
180
|
+
"saas/openai",
|
181
|
+
"--cpus_per_worker",
|
182
|
+
"0.001",
|
183
|
+
"--gpus_per_worker",
|
184
|
+
"0",
|
185
|
+
"--worker_concurrency",
|
186
|
+
"1000",
|
187
|
+
"--num_workers",
|
188
|
+
"1",
|
189
|
+
"--infer_params",
|
190
|
+
f"saas.base_url=https://api.deepseek.com/v1 saas.api_key={api_key} saas.model=deepseek-chat",
|
191
|
+
"--model",
|
192
|
+
"deepseek_chat",
|
193
|
+
]
|
194
|
+
|
195
|
+
try:
|
196
|
+
subprocess.run(deploy_cmd, check=True)
|
197
|
+
print_status("Model deployed successfully", "success")
|
198
|
+
except subprocess.CalledProcessError:
|
199
|
+
print_status("Failed to deploy model", "error")
|
200
|
+
return False
|
201
|
+
|
202
|
+
# Validate the deployment
|
203
|
+
print_status("Validating model deployment", "")
|
204
|
+
try:
|
205
|
+
validation_result = subprocess.run(
|
206
|
+
["easy-byzerllm", "chat", "deepseek_chat", "你好"],
|
207
|
+
capture_output=True,
|
208
|
+
text=True,
|
209
|
+
timeout=30,
|
210
|
+
check=True,
|
211
|
+
)
|
212
|
+
print_status("Model validation successful", "success")
|
213
|
+
except (subprocess.TimeoutExpired, subprocess.CalledProcessError):
|
214
|
+
print_status("Model validation failed", "error")
|
215
|
+
print_status(
|
216
|
+
"You may need to try manually: easy-byzerllm chat deepseek_chat 你好", "warning")
|
217
|
+
return False
|
218
|
+
|
219
|
+
print_status("Environment initialization complete", "success")
|
220
|
+
return True
|
221
|
+
|
222
|
+
|
223
|
+
class ProxyServer:
|
224
|
+
def __init__(self, project_path: str, quick: bool = False):
|
225
|
+
self.app = FastAPI()
|
226
|
+
|
227
|
+
if not quick:
|
228
|
+
# Check the environment if not in quick mode
|
229
|
+
if not check_environment():
|
230
|
+
print(
|
231
|
+
"\033[31mEnvironment check failed. Some features may not work properly.\033[0m")
|
232
|
+
self.setup_middleware()
|
233
|
+
|
234
|
+
self.setup_static_files()
|
235
|
+
|
236
|
+
self.setup_routes()
|
237
|
+
self.client = httpx.AsyncClient()
|
238
|
+
self.project_path = project_path
|
239
|
+
self.auto_coder_runner = AutoCoderRunner(project_path)
|
240
|
+
self.file_group_manager = FileGroupManager(self.auto_coder_runner)
|
241
|
+
|
242
|
+
def setup_middleware(self):
|
243
|
+
self.app.add_middleware(
|
244
|
+
CORSMiddleware,
|
245
|
+
allow_origins=["*"],
|
246
|
+
allow_credentials=True,
|
247
|
+
allow_methods=["*"],
|
248
|
+
allow_headers=["*"],
|
249
|
+
)
|
250
|
+
|
251
|
+
def setup_static_files(self):
|
252
|
+
self.index_html_path = pkg_resources.resource_filename(
|
253
|
+
"auto_coder_web", "web/index.html")
|
254
|
+
self.resource_dir = os.path.dirname(self.index_html_path)
|
255
|
+
self.static_dir = os.path.join(self.resource_dir, "static")
|
256
|
+
self.app.mount(
|
257
|
+
"/static", StaticFiles(directory=self.static_dir), name="static")
|
258
|
+
|
259
|
+
def setup_routes(self):
|
260
|
+
@self.app.on_event("shutdown")
|
261
|
+
async def shutdown_event():
|
262
|
+
await self.client.aclose()
|
263
|
+
|
264
|
+
@self.app.websocket("/ws/terminal")
|
265
|
+
async def terminal_websocket(websocket: WebSocket):
|
266
|
+
session_id = str(uuid.uuid4())
|
267
|
+
await terminal_manager.handle_websocket(websocket, session_id)
|
268
|
+
|
269
|
+
|
270
|
+
@self.app.delete("/api/files/{path:path}")
|
271
|
+
async def delete_file(path: str):
|
272
|
+
try:
|
273
|
+
full_path = os.path.join(self.project_path, path)
|
274
|
+
if os.path.exists(full_path):
|
275
|
+
if os.path.isdir(full_path):
|
276
|
+
import shutil
|
277
|
+
shutil.rmtree(full_path)
|
278
|
+
else:
|
279
|
+
os.remove(full_path)
|
280
|
+
return {"message": f"Successfully deleted {path}"}
|
281
|
+
else:
|
282
|
+
raise HTTPException(
|
283
|
+
status_code=404, detail="File not found")
|
284
|
+
except Exception as e:
|
285
|
+
raise HTTPException(status_code=500, detail=str(e))
|
286
|
+
|
287
|
+
@self.app.get("/", response_class=HTMLResponse)
|
288
|
+
async def read_root():
|
289
|
+
if os.path.exists(self.index_html_path):
|
290
|
+
async with aiofiles.open(self.index_html_path, "r") as f:
|
291
|
+
content = await f.read()
|
292
|
+
return HTMLResponse(content=content)
|
293
|
+
return HTMLResponse(content="<h1>Welcome to Proxy Server</h1>")
|
294
|
+
|
295
|
+
@self.app.get("/api/project-path")
|
296
|
+
async def get_project_path():
|
297
|
+
return {"project_path": self.project_path}
|
298
|
+
|
299
|
+
def get_project_runner(project_path: str) -> AutoCoderRunner:
|
300
|
+
return self.projects[project_path]
|
301
|
+
|
302
|
+
@self.app.post("/api/file-groups")
|
303
|
+
async def create_file_group(request: Request):
|
304
|
+
data = await request.json()
|
305
|
+
name = data.get("name")
|
306
|
+
description = data.get("description", "")
|
307
|
+
group = await self.file_group_manager.create_group(name, description)
|
308
|
+
return group
|
309
|
+
|
310
|
+
@self.app.get("/api/os")
|
311
|
+
async def get_os():
|
312
|
+
return {"os": os.name}
|
313
|
+
|
314
|
+
@self.app.post("/api/file-groups/switch")
|
315
|
+
async def switch_file_groups(request: Request):
|
316
|
+
data = await request.json()
|
317
|
+
group_names = data.get("group_names", [])
|
318
|
+
result = await self.file_group_manager.switch_groups(group_names)
|
319
|
+
return result
|
320
|
+
|
321
|
+
@self.app.delete("/api/file-groups/{name}")
|
322
|
+
async def delete_file_group(name: str):
|
323
|
+
await self.file_group_manager.delete_group(name)
|
324
|
+
return {"status": "success"}
|
325
|
+
|
326
|
+
@self.app.post("/api/file-groups/{name}/files")
|
327
|
+
async def add_files_to_group(name: str, request: Request):
|
328
|
+
data = await request.json()
|
329
|
+
files = data.get("files", [])
|
330
|
+
description = data.get("description")
|
331
|
+
if description is not None:
|
332
|
+
group = await self.file_group_manager.update_group_description(name, description)
|
333
|
+
else:
|
334
|
+
group = await self.file_group_manager.add_files_to_group(name, files)
|
335
|
+
return group
|
336
|
+
|
337
|
+
@self.app.delete("/api/file-groups/{name}/files")
|
338
|
+
async def remove_files_from_group(name: str, request: Request):
|
339
|
+
data = await request.json()
|
340
|
+
files = data.get("files", [])
|
341
|
+
group = await self.file_group_manager.remove_files_from_group(name, files)
|
342
|
+
return group
|
343
|
+
|
344
|
+
@self.app.post("/api/revert")
|
345
|
+
async def revert():
|
346
|
+
try:
|
347
|
+
result = self.auto_coder_runner.revert()
|
348
|
+
return result
|
349
|
+
except Exception as e:
|
350
|
+
raise HTTPException(status_code=500, detail=str(e))
|
351
|
+
|
352
|
+
@self.app.get("/api/file-groups")
|
353
|
+
async def get_file_groups():
|
354
|
+
groups = await self.file_group_manager.get_groups()
|
355
|
+
return {"groups": groups}
|
356
|
+
|
357
|
+
@self.app.get("/api/files")
|
358
|
+
async def get_files():
|
359
|
+
tree = get_directory_tree(self.project_path)
|
360
|
+
return {"tree": tree}
|
361
|
+
|
362
|
+
@self.app.get("/api/completions/files")
|
363
|
+
async def get_file_completions(name: str = Query(...)):
|
364
|
+
"""获取文件名补全"""
|
365
|
+
matches = self.auto_coder_runner.find_files_in_project([name])
|
366
|
+
completions = []
|
367
|
+
project_root = self.auto_coder_runner.project_path
|
368
|
+
for file_name in matches:
|
369
|
+
path_parts = file_name.split(os.sep)
|
370
|
+
# 只显示最后三层路径,让显示更简洁
|
371
|
+
display_name = os.sep.join(
|
372
|
+
path_parts[-3:]) if len(path_parts) > 3 else file_name
|
373
|
+
relative_path = os.path.relpath(file_name, project_root)
|
374
|
+
|
375
|
+
completions.append(CompletionItem(
|
376
|
+
name=relative_path, # 给补全项一个唯一标识
|
377
|
+
path=relative_path, # 实际用于替换的路径
|
378
|
+
display=display_name, # 显示的简短路径
|
379
|
+
location=relative_path # 完整的相对路径信息
|
380
|
+
))
|
381
|
+
return CompletionResponse(completions=completions)
|
382
|
+
|
383
|
+
@self.app.get("/api/completions/symbols")
|
384
|
+
async def get_symbol_completions(name: str = Query(...)):
|
385
|
+
"""获取符号补全"""
|
386
|
+
symbols = self.auto_coder_runner.get_symbol_list()
|
387
|
+
matches = []
|
388
|
+
|
389
|
+
for symbol in symbols:
|
390
|
+
if name.lower() in symbol.symbol_name.lower():
|
391
|
+
relative_path = os.path.relpath(
|
392
|
+
symbol.file_name, self.project_path)
|
393
|
+
matches.append(CompletionItem(
|
394
|
+
name=symbol.symbol_name,
|
395
|
+
path=f"{symbol.symbol_name} ({relative_path}/{symbol.symbol_type.value})",
|
396
|
+
display=f"{symbol.symbol_name}(location: {relative_path})"
|
397
|
+
))
|
398
|
+
return CompletionResponse(completions=matches)
|
399
|
+
|
400
|
+
@self.app.put("/api/file/{path:path}")
|
401
|
+
async def update_file(path: str, request: Request):
|
402
|
+
try:
|
403
|
+
data = await request.json()
|
404
|
+
content = data.get("content")
|
405
|
+
if content is None:
|
406
|
+
raise HTTPException(
|
407
|
+
status_code=400, detail="Content is required")
|
408
|
+
|
409
|
+
full_path = os.path.join(self.project_path, path)
|
410
|
+
|
411
|
+
# Ensure the directory exists
|
412
|
+
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
413
|
+
|
414
|
+
# Write the file content
|
415
|
+
with open(full_path, 'w', encoding='utf-8') as f:
|
416
|
+
f.write(content)
|
417
|
+
|
418
|
+
return {"message": f"Successfully updated {path}"}
|
419
|
+
except Exception as e:
|
420
|
+
raise HTTPException(status_code=500, detail=str(e))
|
421
|
+
|
422
|
+
@self.app.get("/api/file/{path:path}")
|
423
|
+
async def get_file_content(path: str):
|
424
|
+
from .file_manager import read_file_content
|
425
|
+
content = read_file_content(self.project_path, path)
|
426
|
+
if content is None:
|
427
|
+
raise HTTPException(
|
428
|
+
status_code=404, detail="File not found or cannot be read")
|
429
|
+
|
430
|
+
return {"content": content}
|
431
|
+
|
432
|
+
@self.app.get("/api/active-files")
|
433
|
+
async def get_active_files():
|
434
|
+
"""获取当前活动文件列表"""
|
435
|
+
active_files = self.auto_coder_runner.get_active_files()
|
436
|
+
return active_files
|
437
|
+
|
438
|
+
@self.app.get("/api/conf")
|
439
|
+
async def get_conf():
|
440
|
+
return {"conf": self.auto_coder_runner.get_config()}
|
441
|
+
|
442
|
+
@self.app.post("/api/conf")
|
443
|
+
async def config(request: Request):
|
444
|
+
data = await request.json()
|
445
|
+
try:
|
446
|
+
for key, value in data.items():
|
447
|
+
self.auto_coder_runner.configure(key, str(value))
|
448
|
+
return {"status": "success"}
|
449
|
+
except Exception as e:
|
450
|
+
raise HTTPException(status_code=400, detail=str(e))
|
451
|
+
|
452
|
+
@self.app.post("/api/coding")
|
453
|
+
async def coding(request: Request):
|
454
|
+
data = await request.json()
|
455
|
+
query = data.get("query", "")
|
456
|
+
if not query:
|
457
|
+
raise HTTPException(
|
458
|
+
status_code=400, detail="Query is required")
|
459
|
+
return await self.auto_coder_runner.coding(query)
|
460
|
+
|
461
|
+
@self.app.post("/api/chat")
|
462
|
+
async def chat(request: Request):
|
463
|
+
data = await request.json()
|
464
|
+
query = data.get("query", "")
|
465
|
+
if not query:
|
466
|
+
raise HTTPException(
|
467
|
+
status_code=400, detail="Query is required")
|
468
|
+
return await self.auto_coder_runner.chat(query)
|
469
|
+
|
470
|
+
@self.app.get("/api/result/{request_id}")
|
471
|
+
async def get_result(request_id: str):
|
472
|
+
result = await self.auto_coder_runner.get_result(request_id)
|
473
|
+
if result is None:
|
474
|
+
raise HTTPException(
|
475
|
+
status_code=404, detail="Result not found or not ready yet")
|
476
|
+
|
477
|
+
v = {"result": result.value, "status": result.status.value}
|
478
|
+
return v
|
479
|
+
|
480
|
+
@self.app.post("/api/event/get")
|
481
|
+
async def get_event(request: EventGetRequest):
|
482
|
+
request_id = request.request_id
|
483
|
+
if not request_id:
|
484
|
+
raise HTTPException(
|
485
|
+
status_code=400, detail="request_id is required")
|
486
|
+
|
487
|
+
v = self.auto_coder_runner.get_event(request_id)
|
488
|
+
return v
|
489
|
+
|
490
|
+
@self.app.post("/api/event/response")
|
491
|
+
async def response_event(request: EventResponseRequest):
|
492
|
+
request_id = request.request_id
|
493
|
+
if not request_id:
|
494
|
+
raise HTTPException(
|
495
|
+
status_code=400, detail="request_id is required")
|
496
|
+
|
497
|
+
self.auto_coder_runner.response_event(
|
498
|
+
request_id, request.event, request.response)
|
499
|
+
return {"message": "success"}
|
500
|
+
|
501
|
+
@self.app.get("/api/output/{request_id}")
|
502
|
+
async def get_terminal_logs(request_id: str):
|
503
|
+
return self.auto_coder_runner.get_logs(request_id)
|
504
|
+
|
505
|
+
|
506
|
+
def main():
|
507
|
+
parser = argparse.ArgumentParser(description="Proxy Server")
|
508
|
+
parser.add_argument(
|
509
|
+
"--port",
|
510
|
+
type=int,
|
511
|
+
default=8007,
|
512
|
+
help="Port to run the proxy server on (default: 8007)",
|
513
|
+
)
|
514
|
+
parser.add_argument(
|
515
|
+
"--host",
|
516
|
+
type=str,
|
517
|
+
default="0.0.0.0",
|
518
|
+
help="Host to run the proxy server on (default: 0.0.0.0)",
|
519
|
+
)
|
520
|
+
parser.add_argument(
|
521
|
+
"--quick",
|
522
|
+
action="store_true",
|
523
|
+
help="Skip environment check",
|
524
|
+
)
|
525
|
+
args = parser.parse_args()
|
526
|
+
|
527
|
+
proxy_server = ProxyServer(quick=args.quick, project_path=os.getcwd())
|
528
|
+
uvicorn.run(proxy_server.app, host=args.host, port=args.port)
|
529
|
+
|
530
|
+
|
531
|
+
if __name__ == "__main__":
|
532
|
+
main()
|