运行架构
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 接口共享角色、模型、偏好与对话服务。
一轮对话的数据流
- 输入框或 ASR 得到用户文本。
POST /api/chat通过 SSE 返回 delta 与完整句子。- 句子立即进入
/api/tts队列,并进行快速表情动作分析。 - 音频播放时使用幅度驱动 VRM 口型,按句应用表情和 VRMA。
- 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 -RebuildApplicationone-folder 输出为 dist/VirtualCompanion,安装包输出到 dist/installer。公开发布前应加入 Authenticode 签名、时间戳和稳定 Release 下载地址。
数据与并发边界
- 当前是单机单用户模型,角色、历史和记忆使用 JSON 持久化。
- 历史写入和关键配置使用锁或临时文件替换,避免中途写坏。
- TTS 串行化以规避云端 WebSocket 并发冲突。
- CEF 窗口调用通过队列回到所属线程;不能随意销毁后从另一线程重建。
- 设置保存后 sidecar 以退出码 75 请求桌面壳重启服务。
适合继续扩展的方向
- 角色与 VRM、舞台、待机动作和模型构图的统一绑定。
- 服务自检、首次使用引导与更清晰的对话状态机。
- 多显示器、DPI、窗口位置恢复与桌宠行为池。
- 为 API 增加明确的版本前缀前,需要先评估当前前端和桌面壳调用兼容。