运行架构

VirtualCompanion.exe (WinForms 主控)
├─ 选择本地端口并启动 Python sidecar
├─ WebView2 → http://127.0.0.1:<port>/app/
├─ 系统托盘、单实例、窗口与服务重启
└─ shell command long polling

VirtualCompanion.Server.exe / app_launcher.py
├─ FastAPI routers + services
├─ Vue 静态资源
├─ JSON / 音频 / 配置持久化
└─ CEF OSR 桌宠线程 → Win32 分层窗口

主窗口和桌宠不是两个后端实例。它们通过同源 HTTP 接口共享角色、模型、偏好与对话服务。

一轮对话的数据流

  1. 输入框或 ASR 得到用户文本。
  2. POST /api/chat 通过 SSE 返回 delta 与完整句子。
  3. 句子立即进入 /api/tts 队列,并进行快速表情动作分析。
  4. 音频播放时使用幅度驱动 VRM 口型,按句应用表情和 VRMA。
  5. done 事件确认完整回复并持久化历史,完整分析结果可以修正后续表现。
流式生成、句级 TTS 和播放彼此重叠,避免等待完整回复、完整合成后才开始说话。这是 800ms 体验指标的主要工程基础。

CEF 桌宠链路

PetService 在守护线程中创建 TransparentPetWindow。CEF 通过 OSR 回调产生 BGRA 帧,Win32 UpdateLayeredWindow 将其合成到透明窗口。后端用线程安全 JS 队列执行 window.receiveFromMain(...)

用户退出桌宠时只隐藏窗口并保留 CEF 线程。CEF 的 Browser 和消息循环必须继续位于初始化线程,整个应用退出时才真正销毁。

目录职责

backend/FastAPI 路由、服务编排、模型与本地持久化
web/Vue 3 主界面、设置、角色管理、Three.js VRM 舞台与桌宠页面
desktop/WinForms + WebView2 主控、托盘、窗口和 sidecar 生命周期
packaging/PyInstaller spec 与 Inno Setup 安装定义
scripts/开发启动、one-folder 与安装包构建脚本
prompts/角色生成、长期记忆与情感分析提示词
reference_audio/默认声音复刻参考音频

本地运行

环境:Windows、Python 3.11、Node.js 18+。构建桌面壳还需要 .NET 8 SDK。

conda create -n VirtualCompanion python=3.11 -y
conda activate VirtualCompanion
pip install -r requirements.txt

cd web
npm install
npm run build
cd ..

Copy-Item .env.example .env
.\scripts\quickstart.ps1

服务端口由 APP_PORT 决定;留空时从 8000 起选择可用端口。运行中的 Swagger 位于 /docs

构建与发布

# one-folder
.\scripts\build_package.ps1

# 安装包
.\scripts\build_installer.ps1 -AppVersion 0.2.0 -RebuildApplication

one-folder 输出为 dist/VirtualCompanion,安装包输出到 dist/installer。公开发布前应加入 Authenticode 签名、时间戳和稳定 Release 下载地址。

数据与并发边界

  • 当前是单机单用户模型,角色、历史和记忆使用 JSON 持久化。
  • 历史写入和关键配置使用锁或临时文件替换,避免中途写坏。
  • TTS 串行化以规避云端 WebSocket 并发冲突。
  • CEF 窗口调用通过队列回到所属线程;不能随意销毁后从另一线程重建。
  • 设置保存后 sidecar 以退出码 75 请求桌面壳重启服务。

适合继续扩展的方向

  • 角色与 VRM、舞台、待机动作和模型构图的统一绑定。
  • 服务自检、首次使用引导与更清晰的对话状态机。
  • 多显示器、DPI、窗口位置恢复与桌宠行为池。
  • 为 API 增加明确的版本前缀前,需要先评估当前前端和桌面壳调用兼容。