维护手册
最完整的一份运维文档:目录职责、配置体系、用户数据边界与常见故障排查。
飞行雪绒维护手册#
更新时间:2026-07-31
本手册面向维护者和代码代理,说明当前工程边界、常见变更路径和验收方式。开始工作前先读 doc/AI协作规范.md,再按任务阅读专项文档。
1. 事实源与优先级#
发生冲突时按以下顺序判断:
- 可执行源码与测试。
- 本手册和
doc/README.md。 - 事件、游戏包等专项协议文档。
- 根目录 README、贡献和发布说明。
- 历史计划、整改清单和更新日志。
| 内容 | 权威位置 |
|---|---|
| 应用版本 | config/version_info.py |
| 默认配置 | config/config_*.py |
| 用户稀疏覆盖 | config/user_settings.py |
| 用户目录布局 | config/user_storage_paths.py |
| 事件类型与派发 | lib/core/event/center.py |
| 工作台页面元数据 | lib/script/workbench/page_registry.py、settings/schema.py |
| 音乐公开接口 | lib/script/music/ |
| 游戏包契约 | doc/游戏包格式.md、game_packages.py |
| 依赖集合 | requirements*.txt |
| 发行文件边界 | scripts/package_*.py、release_common.py |
2. 启动与退出#
启动链路#
启动程序.bat / 调试模式.bat
-> lib/core/qt_desktop_pet.py
-> lib/script/main.py::main
-> ApplicationState
-> APP_PRE_START / APP_INIT_READY / APP_START / APP_MAIN
ApplicationState 负责单实例、Qt 应用、主窗口、管理器、托盘、预加载和最终清理。长生命周期组件不得绕过它自行结束应用。
主界面就绪后,AnnouncementController 从固定 Gitee RESC 发布槽异步下载桌宠公告。公告文件使用按出现顺序解析的 title、subtitle、text 引号块,可重复出现多个 subtitle 和 text;正文窗口保持紧凑并独立滚动。用户可仅抑制当日自动显示或永久抑制自动显示,状态写入 <用户根>/user/state/announcement.json,最近一次成功内容缓存到 <用户根>/cache/announcement.txt。“界面与动画”页的“不显示公告”复选框读取并修改同一份永久抑制状态,取消勾选不会清除当日抑制。托盘“桌宠公告”入口不受自动显示偏好限制;每次手动打开都先进入加载态并发起独立的无缓存请求,只接受最后一次请求的结果,网络失败时才回退到本地缓存。
退出链路#
正常退出由 ApplicationState.request_exit() 发起,依次停止主窗口、清理运行时服务、清理视觉组件并退出 Qt 事件循环。APP_EXIT 广播退出阶段,APP_QUIT 请求主编排器开始退出。
最后一个退出阶段使用带退出码的 QApplication.exit(),处理 DeferredDelete 后等待 aboutToQuit 确认;未确认时会关闭残留顶层窗口并再次请求正常退出。事件循环返回后还要短暂等待非守护线程结束。15 秒进程级 watchdog 只作为整个退出链路卡死时的最终兜底,正常收尾确认后必须取消。
需要重启时向 APP_QUIT 传入 restart: true。主编排器必须先成功拉起脱离当前进程树的重启 helper,再走完整退出流程并释放单实例锁;helper 等待旧 PID 真正退出后启动新实例。helper 创建失败时不得退出当前实例。重启 helper 不属于本地托管服务,服务清理不得结束它;界面组件也不得自行拉起副本。启动阶段诊断写入 logs/restart.log。
分发包更新使用独立的更新 helper:主进程只并发检测固定 GitHub/Gitee 发布槽、下载并校验 ZIP,成功创建 helper 后通过普通 APP_QUIT 优雅退出,不再由主进程覆盖文件,也不再创建普通重启 helper。更新 helper 必须确认旧 PID 已退出,随后保护 logs/、resc/user/、resc/models/ 和 py.ini,覆盖程序文件、写入更新状态并启动新实例。等待超时或覆盖失败时不得启动半更新实例,诊断写入 logs/update.log。
维护约束:
- 新增长生命周期对象必须提供幂等
cleanup()。 - 事件订阅必须有对称
unsubscribe()。 - 网络流设置有限连接/读取超时,并在 cleanup 时关闭活动响应。
- 子进程保存句柄;先正常终止,超时后结束进程树。
- 后台任务统一使用
lib/core/compute_hub.py,不得新建无所有者线程池。 - 用户点击后必须立即开始的长耗时 I/O 使用
ComputeHub.submit_interactive_io()的保留执行槽,不能排在登录、音乐下载等共享后台队列之后。 os._exit()只能作为最终超时兜底。
3. 模块边界#
核心层 lib/core#
核心层包含事件、绘制、层级、输入、物理、调度、日志和主宠窗口。业务模块可以依赖核心层,核心层不得反向依赖具体 provider 或工作台页面。
- 绘制排序:
render_core.py、render_layer.py - 业务绘制入口:
draw_core.py、unified_draw.py - 窗口层级:
layer_manager.py - 事件中心:
event/center.py - 后台执行:
compute_hub.py
旧 core/object、core/render 包和 topmost_manager.py 已删除,不得恢复兼容壳。
业务层 lib/script#
- AI/聊天:
chat/ - 音乐搜索门面:
music/ - 音乐播放内部实现:
cloudmusic/ - 本地子进程服务:
yuanbao_free_api/、local_hosted_service.py - ONNX 语音推理与安装:
gsvmove/ - 桌面对象:
obj-* - 游戏系统:
gemes/MAIN/ - UI:
ui/ - 工作台元数据与组件:
workbench/
新增跨模块调用时优先使用明确服务接口;事件只用于需要解耦、广播或跨线程切换的场景。
4. 工作台#
工作台采用两级懒加载:启动预加载器不创建工作台;打开总览只创建工作台壳;进入设置页或工具页时才调用页面工厂。
工作台顶栏搜索框左侧的粉青色明暗主题开关保存到 UI.workbench_light_theme,默认关闭为当前暗色主题;开启后使用白色/粉色表面和深灰蓝文字,并通过 CONFIG_UPDATED 热重载工作台样式。“界面与动画”设置页不再提供重复入口。
工作台及其动态创建的控件统一使用 config.font_config.get_ui_font() 注册的 HarmonyOS Sans SC 字体族;控件树刷新时只替换字体族,不覆盖字号、粗细和自定义绘制字体。
相关位置:
- 窗口与宿主:
lib/script/ui/workbench_window.py - 页面注册:
lib/script/workbench/page_registry.py - 设置 schema:
lib/script/workbench/settings/schema.py - 设置布局:
lib/script/workbench/settings/page_layout.py - AI 设置控制器:
lib/script/ui/ai_settings_panel.py
约束:
- 页面元数据使用 dataclass,不转回 legacy dict。
- 新工具页提供无参数 factory,首次访问时创建。
- 页面嵌入后不得保留独立窗口旗标或重复层级注册。
- 页面关闭时释放信号、定时器和后台任务。
- 不把新功能继续堆入
ai_settings_panel.py,新页面放入workbench/或专属模块。 - AI 回复模式是单一路由:福利 API、手动 API、本地 Ollama、规则回复和元宝之间不做失败回退。模式专属配置只在对应模式下显示。
- 福利 API 配置由
lib/script/chat/welfare_api_config.py从 GitHub/Gitee 发布源并发测速获取密钥与地址。模型使用程序内置的固定标识,不依赖服务端实现/models:默认模型为agnes-2.0-flash,“智力提升”开启后使用agnes-2.5-flash;配置下载超时固定 10 秒,首次失败后最多重试 3 次。 - 手动 API 的模型探测只辅助选择该路由的模型:设置面板以当前未保存的地址和密钥异步请求 OpenAI 兼容
/models,失败时保留用户当前输入。模型字段始终允许手工输入;无协议的公网地址按 HTTPS、本机地址按 HTTP 规范化后保存。 - 语音设置在 ONNX 包有效时显示;检测到旧
start_gsvmove.bat、缺失包或损坏包时,面板顶部显示“安装最新语音包”。有效包和损坏包同时提供带确认的后台删除入口,删除后立即刷新为可重新安装状态。安装窗口中的“后台安装”只隐藏界面、不取消任务;再次点击安装入口可恢复进度,后台仅在关键阶段以桌宠气泡提醒。面板开放当前 v2Pro 实际消费的采样温度、Top-K、Top-P、重复惩罚、语速、分句、片段停顿、随机种子和最大解码步数;批处理、流式及 v3/v4 专属兼容字段不显示为有效设置。安装与包管理 UI 位于独立的voice_package_installer.py,不得继续堆入设置面板。
5. 配置与用户数据#
config/config_*.py 只存程序默认值,运行时禁止改写 Python 源文件。普通设置通过 config.user_settings 保存为版本化稀疏 JSON;密钥和登录态使用独立 secrets/state 路径。
默认值: config/config_*.py
用户覆盖: <用户根>/user/settings.json
状态: <用户根>/user/state/
密钥: <用户根>/user/secrets/
缓存: <用户根>/cache/
旧路径只允许一次性迁移读取。迁移必须有唯一 migration id、可重复执行、不覆盖新值,成功后只读写新位置,并提供迁移与幂等测试。
AI 密钥保存到 <用户根>/user/secrets/ai.json。设置面板每次打开都重新读取该文件,不能只使用模块首次导入时的内存值,以保证跨进程写入和重启后的配置一致。
通用配置保存使用 config.general_user_settings.save_general_values();不要在业务模块中自行解析或正则修改配置源码。
6. 事件、调度与绘制#
事件类型只能定义在 EventType。payload 使用字典,新增字段应允许旧订阅者忽略。后台线程发布事件时,由 Qt pump 切回事件中心线程。
修改事件时同步 事件系统使用说明.txt、已注册的事件.txt 以及生产者和消费者测试。
帧、tick、GIF 帧和延迟任务由 TimingManager 负责。不要用散落的永久 QTimer 替代共享调度,除非计时器天然属于控件生命周期。
绘制请求统一使用 DrawCore/RenderCore,窗口置顶统一使用 LayerManager。新增窗口必须选择明确 Layer,并在销毁时 unregister。
7. 音乐与本地服务#
外部音乐调用只使用 lib.script.music.get_music_service()。MusicProvider 负责搜索结果标准化,MusicPlaybackBackend 定义播放运行时契约,cloudmusic 是内部实现。
禁止业务模块访问 backend 私有字段、provider 反向导入 MusicService、恢复 cloudmusic 单例兼容入口或运行时改写 config_music.py。
本地子进程服务复用 local_hosted_service.py。健康检查、端口切换、启动和清理必须可重复调用。
元宝服务源码位于 services/yuanbao-free-api/。发行时 release_common.py 根据当前源码生成 services/bundles/yuanbao-free-api-main.zip,仓库中的旧 zip 不是发行权威源。
元宝本地中转端口被占用时,YuanbaoFreeApiService 会切换到随机本地端口;OpenAI 兼容请求在发送前必须读取 get_yuanbao_local_base_url() 的运行时地址,不能继续使用管理器初始化期缓存的端口。
设置面板的元宝登录区只显示当前可执行操作:未登录时显示“微信登录元宝”,已登录时显示“退出元宝登录”。面板读取已有服务状态必须使用无副作用的 peek_service_status(),不得为检查状态启动服务、切换端口或触发浏览器登录。
GSV 兼容门面不再启动端口 9880 的 HTTP 服务,而是在原语音工作线程中复用单个 ONNX 引擎。格式版本 2 保留 GPT-SoVITS API v2 参数命名;同一格式内影响正确性的模型或推理升级使用独立 runtime_revision,客户端必须拒绝低于当前最低修订的旧包并显示更新入口。语速必须使用 VITS 图内 speed_factor,禁止恢复改变音高的最终波形重采样。当前 revision 3 包内置中文 RoBERTa,RoBERTa 加载失败必须报错,不能退回零特征;参考 HuBERT 提示语义必须保留原生链路的尾静音。安装器提供完全包、默认中等包和节约包三档,优先 ModelScope、回退 Hugging Face;每档为单个 RAR5 solid archive,使用 64 MiB 字典,大小与空间检查以 VoicePackageProfile 的真实发布值为准。语音包格式、单文件下载、安装、用户确认删除、旧运行时清理和随包 UnRAR 边界以 doc/语音包协议.md 为准。安装前不得为定位旧运行时递归扫描用户目录;安装成功后只清理路径记录明确指向的旧外部 GSVmove。包删除必须由服务在推理锁内释放引擎后执行,并限定在固定磁盘的受管理目录;仓库内 lib/script/gsvmove/ 不属于删除目标。
8. 游戏包兼容边界#
游戏包 manifest、目录布局、加载语义和官方包隔离属于稳定契约。内部实现可以收敛,但不得未经迁移修改包格式。
改动前阅读 doc/游戏包格式.md,并运行:
py -3 -m unittest tests.test_game_package_service
py -3 -m unittest tests.test_game_runtime_geometry tests.test_game_runtime_hash_commands
官方源码包位于 lib/script/gemes/packages/official/,发布时生成 zip,不直接把源码目录作为安装包分发。
9. 依赖与发布#
| 文件 | 用途 |
|---|---|
requirements.txt |
桌宠核心运行依赖 |
requirements-service.txt |
核心依赖 + 可选本地服务 |
requirements-dev.txt |
服务依赖 + 测试/开发工具 |
services/yuanbao-free-api/requirements.txt |
服务独立运行环境 |
普通版和绿色版共享清单、敏感配置清洗、官方游戏包及服务 bundle 生成逻辑。绿色版额外处理 Vosk、动画和 Chromium 归档。
两类发行包都必须携带 lib/script/gsvmove/bin/UnRAR.exe 和 LICENSE-UnRAR.txt,但不携带七卷 ONNX 角色模型。解压器固定校验,不允许安装时联网补取。
依赖安装脚本在摘要前以单行动态展示“正在检查依赖”的当前包、检查数、百分比和进度条;随后只保留已有/未安装依赖摘要和两条固定安装进度行。支持 ANSI 的终端使用 pip 风格的青色当前依赖、粉色整体进度与暗色未完成轨道,不支持颜色的终端显示等宽单色回退。进度刷新不得逐包追加日志。
pip 安装调用必须兼容 Python 3.11.6 随附的 pip 23.2.1;单个依赖失败后继续安装后续依赖,并在最终摘要中显示对应 pip 错误原因,不能只列失败包名。genie-tts 依赖的 jieba-fast 0.53 在 PyPI 没有 Python 3.11 Windows wheel,安装器必须先从 resc.net.txt 的 Gitee/GitHub 镜像下载固定的 cp311-win_amd64 wheel,校验内置 SHA-256 后本地安装,再安装 genie-tts,不得回退到用户机器上的 C++ 源码编译。
依赖可用性默认同时检查 pip 元数据和实际导入。genie-tts 的顶层导入会访问外部 GenieData 并产生输出,因此使用 spec:genie_tts 做无副作用的模块规格检查;不得因资源目录尚未安装而反复重装同一个 Python 包。
发布脚本只允许白名单顶层路径。新增发行文件时必须检查两个入口。--dry-run 不下载资源、不写发行包。
桌宠更新器只探测两个固定程序发布槽:GitHub MARK42IRPC/FlyingSnowVelvet-Aemeath 的 PACK release,以及 Gitee Mark42IRPC/Aemeath-AIdeskpet 的“最新包” release。两个源应指向同一份已验收程序快照;更新器并发读取结构化 release API,优先选择发布时间较新的源,时间相同时选择响应更快的源。检查阶段不下载 ZIP;用户确认更新后才开始下载。同 revision 的首选镜像下载失败时可自动切换备用镜像,revision 不同则禁止混用。更新器不扫描 release 列表,因此 RESC 安装依赖仓库不会进入程序更新候选。
固定发布槽当前允许不上传附件:这种情况下使用 tag 自动生成的源码 ZIP,供测试版更新。后续上传真实打包 ZIP 后优先使用 release 附件,并继续保留源码 ZIP 回退能力。
固定发布槽的 tag 名不是应用版本号。更新状态同时记录 release 时间、源和 revision;只有远端发布时间较新,或时间相同但 revision 改变时才提示更新。下载后的覆盖安装由 lib/script/app/update_installer.py 在主进程退出后执行。
10. 验证矩阵#
所有代码任务至少运行:
py -3 -m compileall -q config lib scripts install_deps.py
py -3 -m unittest discover -s tests -p "test_*.py" -q
py -3 scripts/package_release.py --dry-run --version VERIFY
修改绿色版、资源或安装器时追加:
py -3 scripts/package_green_release.py --dry-run --version VERIFY
修改文档时追加:
py -3 scripts/generate_doc_portal.py
验收记录必须写明实际命令、结果和未执行项,不能只写“测试通过”。
11. 常见变更检查表#
新增长生命周期服务#
- 明确所有者和创建入口。
- 提供幂等 cleanup。
- 处理活动响应、线程和子进程。
- 接入主退出链路。
- 增加启动、重复清理和运行中退出测试。
新增工作台页面#
- 注册页面元数据与 factory。
- 保持首次访问前不构造。
- 实现嵌入模式和关闭释放。
- 添加路由、懒加载和布局测试。
新增配置#
- 在默认配置中定义类型和默认值。
- 接入稀疏用户设置。
- 必要时提供一次性迁移。
- 测试默认值、覆盖、错误类型和迁移幂等性。
新增音乐 provider#
- 实现
MusicProvider并返回标准MusicTrack。 - 接入路由、标签和能力声明。
- 测试失败回退、去重和编码边界。