feat: Integrate and serve the WebUI, including Vercel build configuration and Python routes for static files.

This commit is contained in:
CJACK
2026-02-01 16:43:52 +08:00
parent 9956770cb0
commit b17e492ab8
6 changed files with 105 additions and 9 deletions

50
API.md
View File

@@ -49,6 +49,8 @@ Content-Type: application/json
| `stream` | boolean | ❌ | 是否流式输出,默认 `false` |
| `temperature` | number | ❌ | 温度参数0-2 |
| `max_tokens` | number | ❌ | 最大输出 token 数 |
| `tools` | array | ❌ | 工具定义列表OpenAI 格式) |
| `tool_choice` | string | ❌ | 工具选择策略 |
**支持的模型**:
@@ -111,6 +113,54 @@ data: [DONE]
}
```
**工具调用请求示例**:
```json
{
"model": "deepseek-chat",
"messages": [{"role": "user", "content": "北京今天天气怎么样?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的天气",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "城市名称"}
},
"required": ["location"]
}
}
}]
}
```
**工具调用响应格式**:
```json
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [{
"id": "call_xxx",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\": \"北京\"}"
}
}]
},
"finish_reason": "tool_calls"
}]
}
```
---
## 管理接口

View File

@@ -101,3 +101,6 @@ WASM_PATH = resolve_path("DS2API_WASM_PATH", "sha3_wasm_bg.7b9ca65ddd.wasm")
# 模板目录
TEMPLATES_DIR = resolve_path("DS2API_TEMPLATES_DIR", "templates")
# WebUI 静态文件目录
STATIC_ADMIN_DIR = resolve_path("DS2API_STATIC_ADMIN_DIR", "static/admin")

View File

@@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-
"""首页路由"""
"""首页和 WebUI 路由"""
import os
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse, FileResponse
from fastapi.templating import Jinja2Templates
from core.config import TEMPLATES_DIR
from core.config import TEMPLATES_DIR, STATIC_ADMIN_DIR
router = APIRouter()
templates = Jinja2Templates(directory=TEMPLATES_DIR)
@@ -12,3 +14,29 @@ templates = Jinja2Templates(directory=TEMPLATES_DIR)
@router.get("/")
def index(request: Request):
return templates.TemplateResponse("welcome.html", {"request": request})
@router.get("/webui")
@router.get("/webui/{path:path}")
async def webui(request: Request, path: str = ""):
"""提供 WebUI 静态文件"""
# 检查 static/admin 目录是否存在
if not os.path.isdir(STATIC_ADMIN_DIR):
return HTMLResponse(
content="<h1>WebUI not built</h1><p>Run <code>cd webui && npm run build</code> first.</p>",
status_code=404
)
# 如果请求的是具体文件(如 js, css
if path and "." in path:
file_path = os.path.join(STATIC_ADMIN_DIR, path)
if os.path.isfile(file_path):
return FileResponse(file_path)
return HTMLResponse(content="Not Found", status_code=404)
# 否则返回 index.htmlSPA 路由)
index_path = os.path.join(STATIC_ADMIN_DIR, "index.html")
if os.path.isfile(index_path):
return FileResponse(index_path)
return HTMLResponse(content="index.html not found", status_code=404)

View File

@@ -36,6 +36,9 @@ python3 tests/test_unit.py
- WASM 缓存
- 模型配置获取
- 正则表达式模式
- 流式响应解析
- **工具调用解析**`parse_tool_calls`
- **Token 估算**
### 运行 API 集成测试
@@ -58,9 +61,11 @@ python3 tests/test_all.py --verbose
| 类别 | 测试项 |
|-----|--------|
| 基础 | 服务健康检查 |
| OpenAI | 模型列表、非流式对话、流式对话、无效模型处理、认证错误 |
| OpenAI | 模型列表、非流式对话、流式对话、无效模型处理、认证错误、Reasoner 模式 |
| Claude | 模型列表、非流式消息、流式消息、Token 计数 |
| 高级 | 多轮对话、长输入处理、Reasoner 模式 |
| 高级 | 多轮对话、长输入处理 |
| **工具调用** | OpenAI 工具调用(流式/非流式、Claude 工具调用 |
| **搜索模式** | OpenAI 搜索模式 |
### 运行账号测试
@@ -93,7 +98,7 @@ python3 tests/test_accounts.py --all
### 单元测试
```
Ran 13 tests in 8.685s
Ran 32 tests in 9.0s
OK
```
@@ -101,10 +106,10 @@ OK
```
📊 测试报告
总计: 10 个测试
✅ 通过: 10
总计: 18 个测试
✅ 通过: 18
❌ 失败: 0
⏱️ 耗时: 15.32s
⏱️ 耗时: ~60s
📈 通过率: 100.0%
```

View File

@@ -1,15 +1,24 @@
{
"version": 2,
"buildCommand": "cd webui && npm install && npm run build",
"builds": [
{
"src": "app.py",
"use": "@vercel/python"
},
{
"src": "static/admin/**",
"use": "@vercel/static"
}
],
"routes": [
{
"src": "/webui/assets/(.*)",
"dest": "/static/admin/assets/$1"
},
{
"src": "/(.*)",
"dest": "app.py"
}
]
}
}

View File

@@ -22,4 +22,5 @@ export default defineConfig({
outDir: '../static/admin',
emptyOutDir: true,
},
base: '/webui/',
})