7.7 KiB
数字分身 H5 生产接入与部署
1. 接入方式
生产会会在用户已登录后打开以下地址:
https://digital.99hui.com/#/avatar/manage?token=<encodeURIComponent(会会 access token)>
测试环境示例:
http://192.168.1.188:8099/#/avatar/manage?token=<encodeURIComponent(token)>
兼容参数位于域名查询串的形式,但生产统一使用上面的 hash 路由形式。必须对 token 调用 encodeURIComponent,不能拼接用户 ID 代替 token。
免登录流程如下:
- H5 在页面渲染前读取
token,立即通过history.replaceState从地址栏和浏览器历史中移除。 - H5 调用
POST /api/huihui/token/login,不会把会会 token 当作数字分身接口 token 直接使用。 - 后端通过会会生产接口
/im/box/netease换取 BOXIM 凭证,再调用 BOXIM/user/self校验用户身份。 - 后端以返回的
huihuiUserId绑定本地用户,保存会会凭证供 BOXIM 接管功能使用,并签发本系统app_token。 - 浏览器只保存
app_token和非敏感用户资料。会会原始 token 不返回浏览器存储。 - token 无效、过期或上游校验失败时清除旧会话并进入登录页,不会沿用上一位用户的缓存身份。
2. 生产配置
后端 .env 至少配置以下内容,密钥由部署平台注入,禁止提交 Git:
HUIHUI_DEV_MOCK=false
HUIHUI_AUTH_BASE_URL=https://99hui.com/api/usercenter
HUIHUI_PLATFORM_BASE_URL=https://open.99hui.com/api
BOXIM_API_BASE_URL=https://im.99hui.com/api
HUIHUI_APP_ID=<production-app-id>
HUIHUI_ACCESS_ID=<production-access-id>
HUIHUI_ACCESS_SECRET=<production-access-secret>
HUIHUI_CLIENT_CODE=<production-client-code>
BOXIM_TIMEOUT_SECONDS=20
HUIHUI_PAYMENT_BASE_URL=https://open.99hui.com/api/payment-v3
HUIHUI_PAYMENT_CALLBACK_BASE_URL=https://digital.99hui.com
HUIHUI_PAYMENT_CALLBACK_SECRET=<至少32位随机密钥>
HUIHUI_PAYMENT_TIMEOUT_SECONDS=30
DATABASE_URL=sqlite:////data/avatar.db
UPLOAD_DIR=/data/uploads
CHAT_MODEL_CONFIG_URL=http://<huihuisquare-api>/api/ai-models/runtime/digital-avatar
EMBEDDING_API_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
EMBEDDING_API_KEY=<production-embedding-api-key>
EMBEDDING_MODEL=text-embedding-v3
EMBEDDING_BATCH_SIZE=10
VISION_MODEL=qwen3.6-flash
VISION_OCR_MODEL=qwen-vl-ocr
VISION_MAX_OUTPUT_TOKENS=2048
VISION_TIMEOUT_SECONDS=90
VISION_TOKEN_RESERVE=12000
CHAT_IMAGE_MAX_BYTES=8388608
CHAT_IMAGE_MAX_PIXELS=16000000
CHAT_ATTACHMENT_RETENTION_HOURS=24
CHAT_ATTACHMENT_CLEANUP_MINUTES=60
如生产 AI 配置中心不可用,还应提供当前项目支持的 OPENAI_API_KEY、OPENAI_BASE_URL、CHAT_MODEL 等兜底配置。/data 必须挂载持久卷,数据库与知识库文件不可存放在容器临时层。
EMBEDDING_API_URL 同时支持 OpenAI 兼容基础地址(如上面的 /v1)和完整的 /v1/embeddings 地址,后端会统一请求 /embeddings。发布后必须在后端容器内执行一次最小向量探针,确认返回向量数量和维度,而不能只检查 /api/health。
积分充值使用会会支付体系的 payment-v3/payment/pay,渠道值为 WECHAT / ALIPAY,端内支付场景为 APP,微信内 H5 使用 JSAPI。HUIHUI_PAYMENT_CALLBACK_SECRET 只用于为每笔订单生成 HMAC 回调签名,不会发送到前端或直接出现在回调地址中。支付回调确认状态成功且金额与套餐价格完全一致后才增加积分,重复回调不会重复到账。
3. 构建与发布
首次发布前备份数据:
BACKUP_DIR="backups/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$BACKUP_DIR"
cp /srv/digital-avatar/data/avatar.db "$BACKUP_DIR/"
tar -C /srv/digital-avatar/data -czf "$BACKUP_DIR/uploads.tgz" uploads
在发布目录执行:
git fetch origin
git checkout <已验收的提交SHA>
cd digital-avatar-app
docker compose build --pull avatar-backend avatar-frontend
docker compose up -d avatar-backend avatar-frontend
docker compose ps
curl -fsS http://127.0.0.1:8099/api/health
docker compose exec avatar-backend python -c 'import embeddings; v=embeddings.embed(["部署向量探针"]); print(len(v), len(v[0]))'
生产编排应把示例中的测试端口改为内网暴露,由统一 HTTPS 网关接入。后端暂时使用 SQLite,必须保持单实例写入;若扩展为多后端实例,应先迁移到 PostgreSQL,并把延迟接管任务改为共享队列。
4. 网关要求
必须使用 HTTPS。同域部署时,H5 静态资源与 /api/ 由同一域名提供,可避免跨域和 Cookie/来源策略问题。Nginx 关键配置示例:
server_name digital.99hui.com;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://avatar-backend:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 300s;
client_max_body_size 20m;
}
proxy_buffering off 用于数字分身 SSE 流式吐字,client_max_body_size 同时用于知识库文件和聊天图片上传。应用只保存图片识别结果,不保存原图;识别结果 24 小时失效,后台默认每小时清理一次。公开分享图片识别会消耗分身所有者积分,生产网关应针对 /api/public/avatar/*/chat/images 设置每 IP 和每分享令牌的上传频率限制,防止恶意消耗。
网关和应用日志必须关闭完整 URL 查询参数记录,任何异常日志都不得输出 token、Authorization、图片 Base64、病例正文或平台密钥。建议同时设置严格的 Referrer-Policy: no-referrer。
5. 发布验收
- 已登录会会用户通过带 token 链接打开后直接进入
/avatar/manage,不出现登录页或创建新账号页。 - 页面加载后地址栏中不再包含
token,刷新页面仍使用本地app_token正常访问。 - 后端用户绑定的是 BOXIM 返回的
huihuiUserId,不是 BOXIM 内部id;原有数字分身、独立知识库和积分余额均存在。 - A、B 两个会会用户分别进入时只能看到各自的数字分身与知识库,不会继承上一用户缓存。
- 使用过期或伪造 token 时进入登录页并显示凭证失效,不得继续访问旧用户数据。
- 分身聊天 SSE 逐段输出正常,Markdown 正常渲染,知识库优先级和积分扣费正常。
- 开启 BOXIM 主动接管后保持在线,默认三分钟回复、自定义等待时间、已读回执、分身防回环和主人发言暂停均正常。
- 重建容器后数据库、头像、知识库文档仍存在,
/api/health返回成功。 https://digital.99hui.com/api/health可访问,证书域名和有效期正确,HTTP 自动跳转 HTTPS。- 微信和支付宝各创建一笔最小套餐订单,未付款时积分不变;支付成功后回调到账一次,重复回调积分不重复增加。
- 私聊和公开分享各上传 JPG、PNG、WebP 图片并完成追问;上传非图片、超过 8MB 或跨分身附件时必须拒绝。
- 病例图片可以提取可见文字并标记待核对内容,医学影像不作确定诊断;视觉与 OCR 调用分别扣减积分。
- 检查服务器上传目录不残留聊天原图,数据库过期图片识别记录在清理周期后删除,日志不出现 Base64 或病例正文。
6. 回滚
保留上一版前后端镜像标签和发布前数据库/上传文件备份。代码回滚优先切回上一镜像;只有新版本执行了不可逆数据变更时才恢复数据库。恢复前先停止后端写入,恢复后对比用户数、分身数、知识库文档数并完成一次免登录和聊天验收。