Skip to content

Commit 784f122

Browse files
author
shijiashuai
committed
feat: Phase 3 产品体验 + Phase 4 后端增强
## Phase 3: 产品体验 ### 可访问性 (a11y) - 全局 :focus-visible 焦点样式 + prefers-reduced-motion 降级 - 7 个组件补充 ARIA 属性 (aria-label, role, aria-pressed, aria-live) - SettingsDrawer 完整 dialog/tab ARIA 语义 + useFocusTrap 焦点陷阱 - Canvas 区域 role="img" 标注 ### 响应式布局 - 接入 useIsMobile/usePrefersReducedMotion hooks - SettingsDrawer 移动端全宽 + 背景遮罩 - ControlPanel/TopHUD 响应式适配 ### 主题系统 - VoiceInteractionPanel dark: 变体修复 - SettingsDrawer 主题切换按钮 (Sun/Moon) - DigitalHumanViewer/ChatDock reduced motion 支持 ## Phase 4: 后端增强 ### 认证中间件 - AuthMiddleware 支持 X-API-Key header - AUTH_ENABLED/API_KEYS 环境变量配置 - /health 和 / 免认证 ### 会话持久化抽象 - SessionStore 抽象接口 - InMemorySessionStore (默认) + RedisSessionStore (可选) - dialogue.py 重构,移除模块级全局变量 ### Docker 化 - 多阶段 Dockerfile (node + python) - nginx 反向代理 + supervisord 进程管理 - docker-compose.yml 含 Redis 服务 ### WebSocket 骨架 - /ws endpoint + wsClient.ts (未接入主流程) ## 测试 - 前端: 118 测试通过 - 后端: 49 测试通过
1 parent 1d8ee77 commit 784f122

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+4135
-862
lines changed

.claude/settings.local.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"permissions": {
33
"allow": [
4-
"Bash(npx tsc:*)"
4+
"Bash(npx tsc:*)",
5+
"Bash(npx vitest:*)"
56
]
67
}
78
}

.dockerignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules
2+
.git
3+
dist
4+
dist-*
5+
*.pyc
6+
__pycache__
7+
.env
8+
.claude

Dockerfile

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Stage 1: Build frontend
2+
FROM node:18-alpine AS frontend-builder
3+
WORKDIR /app
4+
COPY package.json package-lock.json ./
5+
RUN npm ci
6+
COPY . .
7+
RUN npm run build
8+
9+
# Stage 2: Production
10+
FROM python:3.12-slim
11+
WORKDIR /app
12+
13+
# Install nginx
14+
RUN apt-get update && apt-get install -y --no-install-recommends nginx supervisor && rm -rf /var/lib/apt/lists/*
15+
16+
# Backend setup
17+
COPY server/requirements.txt /app/server/
18+
RUN pip install --no-cache-dir -r /app/server/requirements.txt
19+
COPY server/ /app/server/
20+
21+
# Frontend built assets
22+
COPY --from=frontend-builder /app/dist /usr/share/nginx/html
23+
24+
# Config files
25+
COPY docker/nginx.conf /etc/nginx/sites-available/default
26+
COPY docker/supervisord.conf /etc/supervisor/conf.d/metahuman.conf
27+
28+
EXPOSE 80
29+
CMD ["supervisord", "-n"]

docker-compose.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
version: "3.8"
2+
3+
services:
4+
app:
5+
build: .
6+
ports:
7+
- "3000:80"
8+
environment:
9+
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
10+
- OPENAI_MODEL=${OPENAI_MODEL:-gpt-4o-mini}
11+
- LLM_PROVIDER=${LLM_PROVIDER:-openai}
12+
- TTS_PROVIDER=${TTS_PROVIDER:-edge}
13+
- AUTH_ENABLED=${AUTH_ENABLED:-false}
14+
- API_KEYS=${API_KEYS:-}
15+
- REDIS_URL=redis://redis:6379/0
16+
- LOG_LEVEL=${LOG_LEVEL:-INFO}
17+
depends_on:
18+
redis:
19+
condition: service_healthy
20+
restart: unless-stopped
21+
22+
redis:
23+
image: redis:7-alpine
24+
ports:
25+
- "6379:6379"
26+
healthcheck:
27+
test: ["CMD", "redis-cli", "ping"]
28+
interval: 5s
29+
timeout: 3s
30+
retries: 5
31+
volumes:
32+
- redis_data:/data
33+
restart: unless-stopped
34+
35+
volumes:
36+
redis_data:

docker/nginx.conf

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
server {
2+
listen 80;
3+
server_name _;
4+
root /usr/share/nginx/html;
5+
index index.html;
6+
7+
location / {
8+
try_files $uri $uri/ /index.html;
9+
}
10+
11+
location /v1/ {
12+
proxy_pass http://127.0.0.1:8000;
13+
proxy_http_version 1.1;
14+
proxy_set_header Host $host;
15+
proxy_set_header X-Real-IP $remote_addr;
16+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
17+
proxy_buffering off;
18+
proxy_cache off;
19+
proxy_read_timeout 300s;
20+
}
21+
22+
location /health {
23+
proxy_pass http://127.0.0.1:8000;
24+
}
25+
26+
location /assets/ {
27+
expires 1y;
28+
add_header Cache-Control "public, immutable";
29+
}
30+
}

docker/supervisord.conf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[supervisord]
2+
nodaemon=true
3+
logfile=/dev/null
4+
logfile_maxbytes=0
5+
6+
[program:nginx]
7+
command=nginx -g "daemon off;"
8+
autostart=true
9+
autorestart=true
10+
stdout_logfile=/dev/stdout
11+
stdout_logfile_maxbytes=0
12+
stderr_logfile=/dev/stderr
13+
stderr_logfile_maxbytes=0
14+
15+
[program:backend]
16+
command=uvicorn app.main:app --host 127.0.0.1 --port 8000
17+
directory=/app/server
18+
autostart=true
19+
autorestart=true
20+
stdout_logfile=/dev/stdout
21+
stdout_logfile_maxbytes=0
22+
stderr_logfile=/dev/stderr
23+
stderr_logfile_maxbytes=0
24+
environment=PYTHONUNBUFFERED="1"

docs/architecture.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,51 @@ UI 层尽量“只读 store + 调用高层 action”,避免直接操作底层
8989
1. `visionService` 获取视频帧并运行推理
9090
2. `visionMapper` 输出简化状态(emotion、nod/shake 等)
9191
3. 页面/引擎应用到数字人表现(表情与动作)
92+
93+
## 5. 当前架构评估
94+
95+
- 优点
96+
- 已经形成 `page -> hooks -> orchestrator/service -> store` 的基本分层,`AdvancedDigitalHumanPage` 比早期版本更薄。
97+
- 前端对后端断连有 fallback,适合 Demo/SDK 场景。
98+
- 3D、语音、视觉、对话四条主能力链路已经能独立演进。
99+
- 当前主要问题
100+
- 聊天消息生命周期分散在 hook、orchestrator、store 三处,容易出现占位消息、流式结束、错误清理不同步。
101+
- 传输层当前同时存在普通 HTTP、SSE、预研 WebSocket,但还没有统一的 transport 抽象。
102+
- UI store 同时承载渲染态、会话态、系统态,后续复杂度继续上升时会增加无关重渲染和状态耦合。
103+
- 视觉、语音、3D 渲染都偏浏览器能力驱动,缺少统一的健康状态和性能观测面板。
104+
105+
## 6. 后续技术路线图
106+
107+
### Phase 1: 稳定交互主链路
108+
109+
- 收敛消息生命周期:用户消息、助手占位、流式 token、结束态、错误态由同一条消息状态流管理。
110+
- 补齐流式聊天测试:重点覆盖并发请求、占位消息清理、fallback、TTS 失败。
111+
- 清理高频路径上的无效订阅,优先优化聊天区、HUD、控制面板的 store 订阅方式。
112+
113+
### Phase 2: 统一实时传输层
114+
115+
- 抽象 `chat transport` 接口,屏蔽 `POST /v1/chat``SSE /v1/chat/stream``WebSocket /ws` 的差异。
116+
- 默认保留 SSE,WebSocket 作为增强模式接入,不把页面逻辑和具体传输协议绑定。
117+
- 给 transport 增加连接态、重连策略、超时和 server capability 探测。
118+
- 支持通过 `VITE_CHAT_TRANSPORT=http|sse|websocket` 切换策略,便于灰度验证。
119+
120+
### Phase 3: 拆分状态域
121+
122+
- 将当前 store 按 `session/chat``avatar/runtime``system/connection` 三个域拆分。
123+
- 减少 3D 渲染状态和聊天 UI 状态的相互影响,降低页面级组件重渲染。
124+
- 将可序列化状态和不可序列化运行时对象彻底分开。
125+
126+
### Phase 4: 体验与性能优化
127+
128+
- Viewer 根据设备能力动态调节粒子数、阴影、DPR 和后处理开关。
129+
- 为聊天区、设置面板、模型加载过程补充 skeleton/placeholder,减少跳变感。
130+
- 增加前端性能埋点:首屏加载、模型加载耗时、首 token 时间、完整回复时间。
131+
132+
## 7. 本轮已落地优化
133+
134+
- 修复流式聊天占位消息 `id` 不一致导致的消息不更新问题。
135+
- 修复流式结束回调重复触发问题,避免 UI 状态重复收尾。
136+
- 聊天气泡在流式开始但尚未收到 token 时,展示明确的生成态文案。
137+
- 聊天 hook 改为 selector 订阅,减少因 store 全量订阅带来的额外重渲染。
138+
- 新增统一 `chat transport` 抽象,并让 orchestrator 改为依赖 transport 而不是直接依赖具体协议实现。
139+
- 修复流式降级到 fallback 时丢失 `connectionStatus/error` 的问题。

docs/development.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ npm run preview
4040
- 说明:后端地址
4141
- 本地开发:`http://localhost:8000`
4242
- GitHub Pages 生产环境:`https://<your-render-service>.onrender.com`
43+
- `VITE_CHAT_TRANSPORT`
44+
- 可选;`http``sse``websocket`
45+
- 默认:`auto`(当前优先走 SSE)
4346

4447
## 3. 后端(FastAPI)
4548

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!doctype html>
2-
<html lang="en">
2+
<html lang="en" class="dark">
33
<head>
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />

server/.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,7 @@ CORS_ALLOW_ORIGINS=https://lessup.github.io
2626

2727
# Logging
2828
LOG_LEVEL=INFO
29+
30+
# Auth (disabled by default)
31+
AUTH_ENABLED=false
32+
API_KEYS=

0 commit comments

Comments
 (0)