auto-coder 0.1.308__py3-none-any.whl → 0.1.309__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.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- {auto_coder-0.1.308.dist-info → auto_coder-0.1.309.dist-info}/METADATA +2 -1
- {auto_coder-0.1.308.dist-info → auto_coder-0.1.309.dist-info}/RECORD +10 -10
- autocoder/auto_coder_rag.py +16 -2
- autocoder/command_args.py +11 -1
- autocoder/rag/api_server.py +108 -36
- autocoder/version.py +1 -1
- {auto_coder-0.1.308.dist-info → auto_coder-0.1.309.dist-info}/LICENSE +0 -0
- {auto_coder-0.1.308.dist-info → auto_coder-0.1.309.dist-info}/WHEEL +0 -0
- {auto_coder-0.1.308.dist-info → auto_coder-0.1.309.dist-info}/entry_points.txt +0 -0
- {auto_coder-0.1.308.dist-info → auto_coder-0.1.309.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: auto-coder
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.309
|
|
4
4
|
Summary: AutoCoder: AutoCoder
|
|
5
5
|
Author: allwefantasy
|
|
6
6
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
@@ -61,6 +61,7 @@ Requires-Dist: pydub
|
|
|
61
61
|
Requires-Dist: youtube-transcript-api
|
|
62
62
|
Requires-Dist: SpeechRecognition
|
|
63
63
|
Requires-Dist: pathvalidate
|
|
64
|
+
Requires-Dist: setuptools
|
|
64
65
|
Requires-Dist: mcp ; python_version >= "3.10"
|
|
65
66
|
|
|
66
67
|
<p align="center">
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
autocoder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
autocoder/auto_coder.py,sha256=ifhdnd39tOIDu_4LdYTxjVCnwmpDoOC90RRwD8bhIKU,65983
|
|
3
3
|
autocoder/auto_coder_lang.py,sha256=Rtupq6N3_HT7JRhDKdgCBcwRaiAnyCOR_Gsp4jUomrI,3229
|
|
4
|
-
autocoder/auto_coder_rag.py,sha256=
|
|
4
|
+
autocoder/auto_coder_rag.py,sha256=vOqwBHdK_KwMNUUc8ji_tlZ5DoALAG1rDjWAic3rM-4,34561
|
|
5
5
|
autocoder/auto_coder_rag_client_mcp.py,sha256=QRxUbjc6A8UmDMQ8lXgZkjgqtq3lgKYeatJbDY6rSo0,6270
|
|
6
6
|
autocoder/auto_coder_rag_mcp.py,sha256=-RrjNwFaS2e5v8XDIrKR-zlUNUE8UBaeOtojffBrvJo,8521
|
|
7
7
|
autocoder/auto_coder_runner.py,sha256=bvd1UXYzVT2L-I2ZCkdxy9Ap8P2Q6F2JD-F7QLvaIPc,106545
|
|
@@ -9,12 +9,12 @@ autocoder/auto_coder_server.py,sha256=E3Z829TPSooRSNhuh3_x9yaZi0f5G0Lm0ntoZhjGao
|
|
|
9
9
|
autocoder/benchmark.py,sha256=Ypomkdzd1T3GE6dRICY3Hj547dZ6_inqJbBJIp5QMco,4423
|
|
10
10
|
autocoder/chat_auto_coder.py,sha256=Cp5_m3pCxEDcRrVG1uojTfD8xecdl9FvYtD948TvLsg,25223
|
|
11
11
|
autocoder/chat_auto_coder_lang.py,sha256=p1SUPw1_YBHK69yNViXr6iFhHL-PjFnrXExA2mXJ5ko,21655
|
|
12
|
-
autocoder/command_args.py,sha256=
|
|
12
|
+
autocoder/command_args.py,sha256=Sfn3TVCoijSm937ZFT_JTsjRIB1gtUr-OZvnWLeS2s8,30732
|
|
13
13
|
autocoder/command_parser.py,sha256=fx1g9E6GaM273lGTcJqaFQ-hoksS_Ik2glBMnVltPCE,10013
|
|
14
14
|
autocoder/lang.py,sha256=U6AjVV8Rs1uLyjFCZ8sT6WWuNUxMBqkXXIOs4S120uk,14511
|
|
15
15
|
autocoder/models.py,sha256=AyoZ-Pzy0oyYUmWCxOIRiOImsqboSfRET7LO9-UOuxI,11172
|
|
16
16
|
autocoder/run_context.py,sha256=IUfSO6_gp2Wt1blFWAmOpN0b0nDrTTk4LmtCYUBIoro,1643
|
|
17
|
-
autocoder/version.py,sha256=
|
|
17
|
+
autocoder/version.py,sha256=pYQUD_mrZAZNxc9Lw3mOsln_cgf30rD3GGdAewKlpVU,23
|
|
18
18
|
autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
autocoder/agent/auto_demand_organizer.py,sha256=URAq0gSEiHeV_W4zwhOI_83kHz0Ryfj1gcfh5jwCv_w,6501
|
|
20
20
|
autocoder/agent/auto_filegroup.py,sha256=pBsAkBcpFTff-9L5OwI8xhf2xPKpl-aZwz-skF2B6dc,6296
|
|
@@ -131,7 +131,7 @@ autocoder/privacy/__init__.py,sha256=LnIVvGu_K66zCE-yhN_-dPO8R80pQyedCsXJ7wRqQaI
|
|
|
131
131
|
autocoder/privacy/model_filter.py,sha256=-N9ZvxxDKpxU7hkn-tKv-QHyXjvkCopUaKgvJwTOGQs,3369
|
|
132
132
|
autocoder/pyproject/__init__.py,sha256=ms-A_pocgGv0oZPEW8JAdXi7G-VSVhkQ6CnWFe535Ec,14477
|
|
133
133
|
autocoder/rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
134
|
-
autocoder/rag/api_server.py,sha256=
|
|
134
|
+
autocoder/rag/api_server.py,sha256=StGyxrM-7-W2vYHJq-i_Fv-MHrl9UgVWY272Hd-6VJ4,13090
|
|
135
135
|
autocoder/rag/conversation_to_queries.py,sha256=xwmErn4WbdADnhK1me-h_6fV3KYrl_y1qPNQl1aoI6o,4810
|
|
136
136
|
autocoder/rag/doc_filter.py,sha256=UduVO2mlrngwJICrefjDJTYfdmQ4GcRXrfWDQ7xXksk,14206
|
|
137
137
|
autocoder/rag/document_retriever.py,sha256=5BDqKVJqLPScEnua5S5suXhWuCaALIfPf5obXeJoWfs,8461
|
|
@@ -198,9 +198,9 @@ autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
198
198
|
autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
199
199
|
autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=xuBeWD0YOckqRo8JB1WkVIMOYH6c24m7JfV4svBfPDo,15113
|
|
200
200
|
autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
201
|
-
auto_coder-0.1.
|
|
202
|
-
auto_coder-0.1.
|
|
203
|
-
auto_coder-0.1.
|
|
204
|
-
auto_coder-0.1.
|
|
205
|
-
auto_coder-0.1.
|
|
206
|
-
auto_coder-0.1.
|
|
201
|
+
auto_coder-0.1.309.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
202
|
+
auto_coder-0.1.309.dist-info/METADATA,sha256=PK_1Bf18b0XqyZNBitO_y_KFkBlR2sdlwDwYuJ2HjJM,2747
|
|
203
|
+
auto_coder-0.1.309.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
204
|
+
auto_coder-0.1.309.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
|
|
205
|
+
auto_coder-0.1.309.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
|
|
206
|
+
auto_coder-0.1.309.dist-info/RECORD,,
|
autocoder/auto_coder_rag.py
CHANGED
|
@@ -289,7 +289,11 @@ def main(input_args: Optional[List[str]] = None):
|
|
|
289
289
|
serve_parser.add_argument("--ssl_keyfile", default="", help="")
|
|
290
290
|
serve_parser.add_argument("--ssl_certfile", default="", help="")
|
|
291
291
|
serve_parser.add_argument("--response_role", default="assistant", help="")
|
|
292
|
-
serve_parser.add_argument(
|
|
292
|
+
serve_parser.add_argument(
|
|
293
|
+
"--doc_dir",
|
|
294
|
+
default="",
|
|
295
|
+
help="Document directory path, also used as the root directory for serving static files"
|
|
296
|
+
)
|
|
293
297
|
serve_parser.add_argument("--enable_local_image_host", action="store_true", help=" enable local image host for local Chat app")
|
|
294
298
|
serve_parser.add_argument("--tokenizer_path", default=tokenizer_path, help="")
|
|
295
299
|
serve_parser.add_argument(
|
|
@@ -305,7 +309,17 @@ def main(input_args: Optional[List[str]] = None):
|
|
|
305
309
|
action="store_true",
|
|
306
310
|
help="Monitor mode for the doc update",
|
|
307
311
|
)
|
|
308
|
-
|
|
312
|
+
serve_parser.add_argument(
|
|
313
|
+
"--max_static_path_length",
|
|
314
|
+
type=int,
|
|
315
|
+
default=3000,
|
|
316
|
+
help="Maximum length allowed for static file paths (larger value to better support Chinese characters)"
|
|
317
|
+
)
|
|
318
|
+
serve_parser.add_argument(
|
|
319
|
+
"--enable_nginx_x_accel",
|
|
320
|
+
action="store_true",
|
|
321
|
+
help="Enable Nginx X-Accel-Redirect for static file serving when behind Nginx"
|
|
322
|
+
)
|
|
309
323
|
serve_parser.add_argument(
|
|
310
324
|
"--disable_auto_window",
|
|
311
325
|
action="store_true",
|
autocoder/command_args.py
CHANGED
|
@@ -433,7 +433,11 @@ def parse_args(input_args: Optional[List[str]] = None) -> AutoCoderArgs:
|
|
|
433
433
|
doc_serve_parse.add_argument("--ssl_certfile", default="", help="")
|
|
434
434
|
doc_serve_parse.add_argument(
|
|
435
435
|
"--response_role", default="assistant", help="")
|
|
436
|
-
doc_serve_parse.add_argument(
|
|
436
|
+
doc_serve_parse.add_argument(
|
|
437
|
+
"--doc_dir",
|
|
438
|
+
default="",
|
|
439
|
+
help="Document directory path, also used as the root directory for serving static files"
|
|
440
|
+
)
|
|
437
441
|
doc_serve_parse.add_argument("--tokenizer_path", default="", help="")
|
|
438
442
|
doc_serve_parse.add_argument(
|
|
439
443
|
"--collections", default="", help="Collection name for indexing"
|
|
@@ -453,6 +457,12 @@ def parse_args(input_args: Optional[List[str]] = None) -> AutoCoderArgs:
|
|
|
453
457
|
action="store_true",
|
|
454
458
|
help="Monitor mode for the doc update",
|
|
455
459
|
)
|
|
460
|
+
doc_serve_parse.add_argument(
|
|
461
|
+
"--max_static_path_length",
|
|
462
|
+
type=int,
|
|
463
|
+
default=1000,
|
|
464
|
+
help="Maximum length allowed for static file paths"
|
|
465
|
+
)
|
|
456
466
|
|
|
457
467
|
agent_parser = subparsers.add_parser("agent", help="Run an agent")
|
|
458
468
|
agent_subparsers = agent_parser.add_subparsers(dest="agent_command")
|
autocoder/rag/api_server.py
CHANGED
|
@@ -49,6 +49,8 @@ TIMEOUT_KEEP_ALIVE = 5 # seconds
|
|
|
49
49
|
# timeout in 10 minutes. Streaming can take longer than 3 min
|
|
50
50
|
TIMEOUT = float(os.environ.get("BYZERLLM_APISERVER_HTTP_TIMEOUT", 600))
|
|
51
51
|
|
|
52
|
+
# Static file serving security settings
|
|
53
|
+
|
|
52
54
|
router_app = FastAPI()
|
|
53
55
|
|
|
54
56
|
|
|
@@ -178,46 +180,51 @@ async def embed(body: EmbeddingCompletionRequest):
|
|
|
178
180
|
)
|
|
179
181
|
|
|
180
182
|
@router_app.get("/static/{full_path:path}")
|
|
181
|
-
async def
|
|
182
|
-
|
|
183
|
-
allowed_file_type = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp']
|
|
183
|
+
async def serve_static_file(full_path: str, request: Request):
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
raise FileNotFoundError(f"File not found: {file_path}")
|
|
197
|
-
|
|
198
|
-
# 异步读取文件内容
|
|
199
|
-
async with aiofiles.open(file_path, "rb") as f:
|
|
200
|
-
content = await f.read()
|
|
201
|
-
|
|
185
|
+
try:
|
|
186
|
+
# 路径安全检查已经在中间件中完成
|
|
187
|
+
# 直接使用规范化的路径
|
|
188
|
+
file_path = os.path.join("/", os.path.normpath(unquote(full_path)))
|
|
189
|
+
|
|
190
|
+
# 检查文件是否存在
|
|
191
|
+
if not os.path.exists(file_path):
|
|
192
|
+
raise FileNotFoundError(f"File not found: {file_path}")
|
|
193
|
+
|
|
194
|
+
# 如果启用了Nginx X-Accel-Redirect,使用X-Accel特性
|
|
195
|
+
if hasattr(request.app.state, "enable_nginx_x_accel") and request.app.state.enable_nginx_x_accel:
|
|
202
196
|
# 获取文件的 MIME 类型
|
|
203
197
|
content_type = mimetypes.guess_type(file_path)[0]
|
|
204
198
|
if not content_type:
|
|
205
199
|
content_type = "application/octet-stream"
|
|
206
200
|
|
|
207
|
-
#
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
201
|
+
# 返回带X-Accel-Redirect头的响应
|
|
202
|
+
# 通过添加X-Accel-Redirect头告诉Nginx直接提供该文件
|
|
203
|
+
# 注意:Nginx配置必须正确设置内部路径映射
|
|
204
|
+
response = Response(content="", media_type=content_type)
|
|
205
|
+
response.headers["X-Accel-Redirect"] = f"/internal{file_path}"
|
|
206
|
+
return response
|
|
207
|
+
|
|
208
|
+
# 默认行为:异步读取文件内容
|
|
209
|
+
async with aiofiles.open(file_path, "rb") as f:
|
|
210
|
+
content = await f.read()
|
|
211
|
+
|
|
212
|
+
# 获取文件的 MIME 类型
|
|
213
|
+
content_type = mimetypes.guess_type(file_path)[0]
|
|
214
|
+
if not content_type:
|
|
215
|
+
content_type = "application/octet-stream"
|
|
216
|
+
|
|
217
|
+
# 返回文件内容
|
|
218
|
+
return Response(content=content, media_type=content_type)
|
|
219
|
+
except FileNotFoundError as e:
|
|
220
|
+
logger.error(f"File not found: {str(e)}")
|
|
221
|
+
raise HTTPException(status_code=404, detail=f"File not found: {str(e)}")
|
|
222
|
+
except PermissionError as e:
|
|
223
|
+
logger.error(f"Permission denied: {str(e)}")
|
|
224
|
+
raise HTTPException(status_code=403, detail=f"Permission denied: {str(e)}")
|
|
225
|
+
except Exception as e:
|
|
226
|
+
logger.error(f"Error serving file: {str(e)}")
|
|
227
|
+
raise HTTPException(status_code=500, detail=f"Error serving file: {str(e)}")
|
|
221
228
|
|
|
222
229
|
class ServerArgs(BaseModel):
|
|
223
230
|
host: str = None
|
|
@@ -234,14 +241,38 @@ class ServerArgs(BaseModel):
|
|
|
234
241
|
response_role: str = "assistant"
|
|
235
242
|
ssl_keyfile: str = None
|
|
236
243
|
ssl_certfile: str = None
|
|
237
|
-
doc_dir: str = ""
|
|
238
|
-
tokenizer_path: Optional[str] = None
|
|
244
|
+
doc_dir: str = "" # Document directory path, also used as the root directory for serving static files
|
|
245
|
+
tokenizer_path: Optional[str] = None
|
|
246
|
+
max_static_path_length: int = int(os.environ.get("BYZERLLM_MAX_STATIC_PATH_LENGTH", 3000)) # Maximum length allowed for static file paths (larger value to better support Chinese characters)
|
|
247
|
+
enable_nginx_x_accel: bool = False # Enable Nginx X-Accel-Redirect for static file serving
|
|
239
248
|
|
|
240
249
|
def serve(llm:ByzerLLM, args: ServerArgs):
|
|
241
250
|
|
|
242
251
|
logger.info(f"ByzerLLM API server version {version}")
|
|
243
252
|
logger.info(f"args: {args}")
|
|
244
253
|
|
|
254
|
+
# 设置静态文件路径长度限制
|
|
255
|
+
max_path_length = args.max_static_path_length
|
|
256
|
+
logger.info(f"Maximum static file path length: {max_path_length}")
|
|
257
|
+
|
|
258
|
+
# 存储Nginx X-Accel设置到应用状态
|
|
259
|
+
router_app.state.enable_nginx_x_accel = args.enable_nginx_x_accel
|
|
260
|
+
if args.enable_nginx_x_accel:
|
|
261
|
+
logger.info("Nginx X-Accel-Redirect enabled for static file serving")
|
|
262
|
+
|
|
263
|
+
# 确定允许访问的静态文件目录
|
|
264
|
+
# 优先级:1. 环境变量 BYZERLLM_ALLOWED_STATIC_DIR
|
|
265
|
+
# 2. 命令行参数 doc_dir
|
|
266
|
+
# 3. 默认值 "/tmp"
|
|
267
|
+
allowed_static_dir = os.environ.get("BYZERLLM_ALLOWED_STATIC_DIR")
|
|
268
|
+
if not allowed_static_dir and args.doc_dir:
|
|
269
|
+
allowed_static_dir = args.doc_dir
|
|
270
|
+
if not allowed_static_dir:
|
|
271
|
+
allowed_static_dir = "/tmp"
|
|
272
|
+
|
|
273
|
+
allowed_static_abs = os.path.abspath(allowed_static_dir)
|
|
274
|
+
logger.info(f"Static files root directory: {allowed_static_abs}")
|
|
275
|
+
|
|
245
276
|
router_app.add_middleware(
|
|
246
277
|
CORSMiddleware,
|
|
247
278
|
allow_origins=args.allowed_origins,
|
|
@@ -250,6 +281,47 @@ def serve(llm:ByzerLLM, args: ServerArgs):
|
|
|
250
281
|
allow_headers=args.allowed_headers,
|
|
251
282
|
)
|
|
252
283
|
|
|
284
|
+
# Add static file security middleware
|
|
285
|
+
@router_app.middleware("http")
|
|
286
|
+
async def static_file_security(request: Request, call_next):
|
|
287
|
+
# Only apply to static routes
|
|
288
|
+
if request.url.path.startswith("/static/"):
|
|
289
|
+
# Extract the full_path from the URL
|
|
290
|
+
path_parts = request.url.path.split("/static/", 1)
|
|
291
|
+
if len(path_parts) > 1:
|
|
292
|
+
full_path = path_parts[1]
|
|
293
|
+
|
|
294
|
+
# Check path length
|
|
295
|
+
if len(full_path) > max_path_length:
|
|
296
|
+
logger.warning(f"Path too long: {len(full_path)} > {max_path_length}")
|
|
297
|
+
return JSONResponse(
|
|
298
|
+
content={"error": "Path too long"},
|
|
299
|
+
status_code=401
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
# Add warning when path length approaches the limit (80% of max)
|
|
303
|
+
if len(full_path) > (max_path_length * 0.8):
|
|
304
|
+
logger.warning(f"Path length approaching limit: {len(full_path)} is {(len(full_path) / max_path_length * 100):.1f}% of max ({max_path_length})")
|
|
305
|
+
|
|
306
|
+
# Decode and normalize path
|
|
307
|
+
decoded_path = unquote(full_path)
|
|
308
|
+
normalized_path = os.path.normpath(decoded_path)
|
|
309
|
+
|
|
310
|
+
# Check if path is in allowed directory
|
|
311
|
+
abs_path = os.path.abspath(os.path.join("/", normalized_path))
|
|
312
|
+
|
|
313
|
+
# 使用预先计算好的allowed_static_abs
|
|
314
|
+
is_allowed = abs_path.startswith(allowed_static_abs)
|
|
315
|
+
|
|
316
|
+
if not is_allowed:
|
|
317
|
+
logger.warning(f"Unauthorized path access: {abs_path}")
|
|
318
|
+
return JSONResponse(
|
|
319
|
+
content={"error": "Unauthorized path"},
|
|
320
|
+
status_code=401
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
return await call_next(request)
|
|
324
|
+
|
|
253
325
|
if token := os.environ.get("BYZERLLM_API_KEY") or args.api_key:
|
|
254
326
|
|
|
255
327
|
@router_app.middleware("http")
|
autocoder/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.309"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|