运行架构与生命周期
宿主怎么发现你的插件、什么时候实例化、什么时候禁止启用、谁和谁互斥。
1. 流水线与插件插入点
宿主以流水线为中心:音频/字幕进来 → 识别 → 翻译 → 展示/朗读。插件挂在明确的扩展点上:
[音频捕获 / 浏览器字幕]
│
▼
process_audio ← middleware
│
▼
VAD 断句
│
▼
ASR 识别 ← asr Provider
│
▼
process_transcript ← middleware
│
▼
术语 Prompt 注入 + MT ← mt Provider + glossary
│
▼
process_translation ← middleware
│
├──► UI 字幕
└──► TTS 朗读 ← tts Provider
│
▼
process_tts_audio ← middleware
│
▼
声卡播放- 中间件按
priority升序执行(数字越小越先跑,默认 100)。单个中间件抛异常会被隔离,不拖垮整条链。 - 术语库只作用于已启用的词库:按当前
source_lang→target_lang过滤词条 → 翻译前注入提示词 / 原文侧校正 →mt.translate(...)→ 中间件改译文 → 术语正/反双向替换。云端千问 ASR 另会把词表转为即时热词。 interpretation是旁路:宿主切入同传模式后不再挂载/驱动标准 ASR → MT → TTS 流水线, 音频帧直接进同传 Provider(见 interpretation)。- 浏览器字幕(
caption_bridge)走feed_direct_caption轻量路径。
2. 发现与加载
本地 extensions/ ──┐
%APPDATA%/transbox/extensions/ ─┼─► PluginRegistry 扫描 mod.json ─► 按 type 挂载
Steam 创意工坊 content/<AppID>/ ─┤
<数据目录>/workshop/<id>/ ─┘ (仅自发行版)按 type 分发:
| type | 挂载方式 |
|---|---|
glossary / i18n / theme | 作为数据挂载(词库 / 字典 / 样式令牌),不 import Python |
asr / mt / tts / middleware / assistant / interpretation / tool | importlib 加载 Python 类,按需实例化 |
caption_bridge / caption_extractor | 接进字幕桥链路(见 caption_extractor) |
同 id 优先级:local > steam > web。 随应用发布的 bundled 插件可被工坊版本覆盖——仅当工坊版本 semver 更高。
type=tool的已启用插件在扫描阶段就会预加载实例(因为要注册热键)。 所以tool插件的initialize()会在启动时跑——里面别做重活。
3. 生命周期
发现 → 解析 mod.json →(启用时)实例化 + initialize(config) → 使用 → 停用 shutdown()| 阶段 | 宿主动作 | 你的责任 |
|---|---|---|
| 扫描 | 读 mod.json、跑依赖门禁、恢复上次启用状态 | 清单写正确 |
| 启用 | 建实例、调 initialize(config) | 只做准备:解析配置、检查文件;不启服务、不加载权重 |
| 使用 | 宿主按需调 ensure_loaded() / 引擎接口 / action_* | 请求入口自己兜底「确保就绪」 |
| 改配置 | 持久化 + 调 update_config(delta) + 广播 config.changed | 热同步内部状态 |
| 停用 / 退出 / 释放显存 | 调 shutdown() → unregister_plugin_hotkeys / close_plugin_windows / 取消事件订阅 | 必须 kill 自己的子进程 |
| 卸载 | 从 sys.path 回收 libs/ vendor/ | 不要在其他地方留状态 |
外部插件(非内置)的
initialize()跑在后台线程,宿主在需要前会调wait_async_init()等它收敛。所以initialize里阻塞几秒不会卡 UI —— 但也不要用它启动服务。
4. 双轨分流与单例复用
自 v0.2 起,入站(上轨 🎧 对方/系统声音)与出站(下轨 🎙️ 我方麦克风)在 ASR / MT / TTS 三层全链路解耦:
- 插件作者零改动:ASR / MT / TTS 插件只遵循标准 Provider 接口,不必为双轨写特殊逻辑。
- 宿主智能分流:流水线按数据流向(
source="peer"/"self")自动分发到对应的活跃引擎。 - 显存安全单例复用:上下轨选中同一模型时,宿主严格复用同一实例引用(
outbound is inbound), 保持 1 倍显存开销;并发调用由引擎内部锁保护。 - 静默旁路:下轨未分配(
none)时,下轨音频流与推理完全短路,零 CPU/GPU/网络开销。
对插件的实际要求只有两条:
- 实现标准的 Provider 接口(见 Provider 签名);
- 支持流式的引擎,若要能同时服务两轨,需返回
supports_concurrent_streams = True(底层是单活句柄就返回False,宿主会自动降级另一轨)。
5. 启用与互斥规则
每类 type 的启用 / 停用动作:
| type | 启用时 | 停用时 |
|---|---|---|
glossary | 注册进全局术语管理器 | 注销 |
i18n | 切换到该语言;与其他第三方语言包互斥 | 若当前是该语言则回退 zh-CN |
theme(full) | 应用主题;与其他 full 主题互斥 | 回退默认主题 |
| 同插槽 UI 扩展 | 占用同一插槽时互斥停用他人 | 移除该插槽组件 |
asr / mt / tts | 可设为当前引擎 | 若是活跃引擎则回退到其它已启用引擎 |
interpretation | 切入同传模式;旁路标准 ASR+MT+TTS | 退出同传并回退标准流水线 |
middleware | 挂入中间件管理器 | 卸载 |
caption_bridge | 联动 Web 字幕服务 | 联动关闭服务 |
| 内置默认主题 | 禁止禁用 | — |
通用规则:
- 启用即生效 / 停用即回退。
- 同类引擎互斥:
asr/mt/tts/interpretation各自只有一个「当前引擎」, 由用户在设置页选定(set_active_provider)。生效引擎只是配置变更,不会预热或加载模型。 - UI 插槽互斥(仅这些槽位,同级之间):
overlay_background、caption_view、audio_level、alert_capsule、overlay_decorations、settings_background、history_background、dialog_background、window_background、copilot_window。 - 全量主题(
style_layer=full)与局部 UI 插槽扩展可以并存 —— 启用波形条不会把用户的主题踢下线。 settings_view不参与任何互斥:每个插件有自己的设置表单。- i18n 整包语言包互斥(同一时间只有一个界面语言)。
- 显示/展示类插件可多开:
glossary、middleware、tool、assistant。
6. 依赖门禁(三处)
宿主在三道关口检查 requires_plugins / requires_runtime:
| 时机 | 行为 |
|---|---|
| 启动扫描 | 依赖未就位(未安装 / 未启用 / 版本过低 / 运行库缺失)→ 强制停用该插件 |
| 打开启用开关 | 拒绝启用 + 浮层提示(插件名、缺什么、怎么处理) |
| 选为 ASR/MT/TTS 引擎 | 拒绝(与启用同一道门禁) |
| 启动同传 | 就绪检查返回 missing_dependency → 阻断并给人话原因 |
宿主不会静默安装前置插件(含代码的插件不允许静默安装);卡片上提供「安装 / 启用 / 更新 / 下载运行库」入口,由用户点。
