mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-05 00:45:29 +08:00
feat: Integrate and serve the WebUI, including Vercel build configuration and Python routes for static files.
This commit is contained in:
50
API.md
50
API.md
@@ -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"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 管理接口
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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.html(SPA 路由)
|
||||
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)
|
||||
|
||||
@@ -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%
|
||||
```
|
||||
|
||||
|
||||
11
vercel.json
11
vercel.json
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -22,4 +22,5 @@ export default defineConfig({
|
||||
outDir: '../static/admin',
|
||||
emptyOutDir: true,
|
||||
},
|
||||
base: '/webui/',
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user