jitsi-windows-local-translation

Windows 11 上部署 Jitsi Meet,并实现局域网实时语音翻译字幕

本文记录一个可复现的测试方案:在 Windows 11 上通过 WSL2 和 Docker Desktop 运行 Jitsi Meet,再接入完全位于 Docker 内网的 Whisper/NLLB 翻译适配器,实现"中文讲话、英文字幕;中文讲话、阿拉伯语字幕"等多语言实时字幕效果。

本案例重点是测试、内网和小规模使用。它不是面向公网生产环境的最终架构。

一、Jitsi Meet 是什么

Jitsi Meet 是一套开源的视频会议解决方案,支持浏览器和移动端访问,也可以通过 Docker 自行部署。它的核心组件包括:

  • Jitsi Meet Web:浏览器会议页面。
  • Prosody:XMPP 信令服务器,负责会议状态和参与者协商。
  • Jicofo:会议控制组件,负责会议编排和桥接服务调度。
  • Jitsi Videobridge(JVB):音视频 SFU,负责转发参会者的音视频流。
  • 可选扩展:录制、直播、电话接入、Etherpad、转写和语音翻译等。

Jitsi 的基本会议功能包括摄像头、麦克风、屏幕共享、聊天、邀请链接、多人会议和移动端浏览器访问。Jitsi 官方文档将它定位为可以自行托管的开源视频会议平台;官方 Docker 方案适合快速部署和测试。

参考:

二、Jitsi 适合做什么

适合的场景

场景 适合原因
公司内网会议 音视频和业务数据可以留在企业网络内,部署成本较低
跨语言内部沟通 可以为不同参会者显示不同目标语言字幕
远程培训和教学 屏幕共享、多人会议和字幕可以组合使用
客服、技术支持和远程协作 可以通过会议链接快速加入,不强制安装客户端
功能验证和原型开发 开源、可修改,适合验证 WebRTC、转写和 AI 翻译方案

不适合直接照搬到生产环境的场景

  • 面向公网的大规模会议平台。
  • 对延迟、准确率和高并发有严格 SLA 的实时翻译服务。
  • 尚未完成身份认证、审计、备份和模型授权确认的正式业务系统。
  • 涉及高度敏感内容、但还没有完成数据流向和日志策略评审的会议。

Jitsi 本身可以作为可靠的视频会议基础,但"实时翻译"还取决于语音识别模型、翻译模型、硬件性能、网络质量和领域词汇。会议功能稳定,不代表 AI 字幕一定准确。

三、本案例的最终效果

会议中的每个人可以独立选择目标语言:

  1. A 说中文。
  2. B 选择 English,看到英文字幕。
  3. C 选择 العربية,看到阿拉伯语字幕。
  4. 识别结果中带有说话人信息,字幕可以区分是谁发言。
  5. 原始会议声音保持不变,本方案主要实现文字字幕翻译,不合成翻译语音。

图中是实际测试截图。发布到公网博客前,建议根据需要将局域网 IP、会议名称和参会者名称打码或替换。

四、整体架构

4.1 数据流

#mermaid-svg-IoZ5XKr0PlFHbs8k{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-IoZ5XKr0PlFHbs8k .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-IoZ5XKr0PlFHbs8k .error-icon{fill:#552222;}#mermaid-svg-IoZ5XKr0PlFHbs8k .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IoZ5XKr0PlFHbs8k .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IoZ5XKr0PlFHbs8k .marker.cross{stroke:#333333;}#mermaid-svg-IoZ5XKr0PlFHbs8k svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IoZ5XKr0PlFHbs8k p{margin:0;}#mermaid-svg-IoZ5XKr0PlFHbs8k .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-IoZ5XKr0PlFHbs8k .cluster-label text{fill:#333;}#mermaid-svg-IoZ5XKr0PlFHbs8k .cluster-label span{color:#333;}#mermaid-svg-IoZ5XKr0PlFHbs8k .cluster-label span p{background-color:transparent;}#mermaid-svg-IoZ5XKr0PlFHbs8k .label text,#mermaid-svg-IoZ5XKr0PlFHbs8k span{fill:#333;color:#333;}#mermaid-svg-IoZ5XKr0PlFHbs8k .node rect,#mermaid-svg-IoZ5XKr0PlFHbs8k .node circle,#mermaid-svg-IoZ5XKr0PlFHbs8k .node ellipse,#mermaid-svg-IoZ5XKr0PlFHbs8k .node polygon,#mermaid-svg-IoZ5XKr0PlFHbs8k .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IoZ5XKr0PlFHbs8k .rough-node .label text,#mermaid-svg-IoZ5XKr0PlFHbs8k .node .label text,#mermaid-svg-IoZ5XKr0PlFHbs8k .image-shape .label,#mermaid-svg-IoZ5XKr0PlFHbs8k .icon-shape .label{text-anchor:middle;}#mermaid-svg-IoZ5XKr0PlFHbs8k .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-IoZ5XKr0PlFHbs8k .rough-node .label,#mermaid-svg-IoZ5XKr0PlFHbs8k .node .label,#mermaid-svg-IoZ5XKr0PlFHbs8k .image-shape .label,#mermaid-svg-IoZ5XKr0PlFHbs8k .icon-shape .label{text-align:center;}#mermaid-svg-IoZ5XKr0PlFHbs8k .node.clickable{cursor:pointer;}#mermaid-svg-IoZ5XKr0PlFHbs8k .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-IoZ5XKr0PlFHbs8k .arrowheadPath{fill:#333333;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-IoZ5XKr0PlFHbs8k .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IoZ5XKr0PlFHbs8k .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-IoZ5XKr0PlFHbs8k .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IoZ5XKr0PlFHbs8k .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-IoZ5XKr0PlFHbs8k .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IoZ5XKr0PlFHbs8k .cluster text{fill:#333;}#mermaid-svg-IoZ5XKr0PlFHbs8k .cluster span{color:#333;}#mermaid-svg-IoZ5XKr0PlFHbs8k div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-IoZ5XKr0PlFHbs8k .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-IoZ5XKr0PlFHbs8k rect.text{fill:none;stroke-width:0;}#mermaid-svg-IoZ5XKr0PlFHbs8k .icon-shape,#mermaid-svg-IoZ5XKr0PlFHbs8k .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IoZ5XKr0PlFHbs8k .icon-shape p,#mermaid-svg-IoZ5XKr0PlFHbs8k .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-IoZ5XKr0PlFHbs8k .icon-shape .label rect,#mermaid-svg-IoZ5XKr0PlFHbs8k .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IoZ5XKr0PlFHbs8k .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-IoZ5XKr0PlFHbs8k .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-IoZ5XKr0PlFHbs8k :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} HTTPS :8443
WebRTC 音视频
配置转写/翻译连接
Opus WebSocket
transcription-result
参会者浏览器
Jitsi Web / Nginx
Jitsi Videobridge
Prosody XMPP
Jicofo 会议控制
local-translation
Opus 解码 + VAD
Whisper small

语音识别
共享识别结果
NLLB-600M INT8

多目标语言翻译
models 持久化缓存

4.2 每个部分的实现点

部分 实现方式 关键配置或代码
Windows 宿主机 Windows 11 + WSL2 + Docker Desktop Docker Desktop 使用 WSL2 后端
Web 入口 Jitsi Web/Nginx PUBLIC_URL=https://<局域网IP>:8443
音视频媒体 JVB 转发 WebRTC 防火墙放行 10000/udp
会议控制 Prosody + Jicofo Jicofo 负责建立转写/翻译 WebSocket
语音输入 JVB 输出参会者 Opus 音频 不开放翻译服务的局域网端口
语音识别 Faster-Whisper small,CPU,INT8 支持 LOCAL_SOURCE_LANGUAGE=zh 等源语言提示
文本翻译 NLLB-200 distilled 600M 本地运行,输出多个目标语言字幕
参会者语言 前端翻译菜单 每个参会者可以独立选择目标语言
说话人显示 端点 ID 映射到 Jitsi participant name 字幕显示说话人名称
隐私日志 后端不打印原文和译文 只记录语言、标签、字符数、耗时和错误
数据持久化 Docker volume 模型缓存存放在 local-translation/models

五、为什么 Windows 需要 WSL2 和 Docker Desktop

Jitsi 的服务端组件主要运行在 Linux 容器中,Windows 不适合直接以原生 Windows 服务的方式部署完整 Jitsi 服务。Windows 11 上更容易复现的路线是:

text 复制代码
Windows 11
  └─ WSL2 / Virtual Machine Platform
      └─ Docker Desktop(WSL2 backend)
          └─ Jitsi Docker Compose

这套方式适合测试和内网小规模使用。正式公网环境通常更建议使用独立的 Linux 服务器或云主机,以获得更稳定的网络、端口、资源隔离和运维能力。

六、部署前准备

6.1 硬件和系统

  • Windows 11 64 位。
  • BIOS/UEFI 已开启硬件虚拟化。
  • 已启用 WSL2 和 Virtual Machine Platform。
  • 已安装 Ubuntu WSL2 发行版。
  • 已安装 Docker Desktop,并启用 WSL2 后端。
  • 建议至少 8 GB 内存;本案例的 Whisper 和 NLLB 模型会占用较多内存。
  • 如果使用 CPU 推理,建议有较新的多核处理器。

6.2 网络和端口

内网测试至少需要:

端口 协议 用途
8443 TCP HTTPS 网页访问
10000 UDP Jitsi WebRTC 音视频媒体

local-translation38030 只在 Docker 内部网络使用,不需要对局域网开放。

本案例局域网地址为:

text 复制代码
https://10.27.0.253:8443

实际部署时必须替换成 Windows 主机当前的局域网 IPv4 地址。若路由器通过 DHCP 更换了地址,需要同步修改 PUBLIC_URLJVB_ADVERTISE_IPS

七、获取 Jitsi Docker 配置

官方建议使用 Docker 项目的稳定版发布包,而不是直接把开发分支当作生产部署代码。本文案例使用:

text 复制代码
stable-11146-2

后续复现时可以使用官方最新稳定版,但要注意配置目录和环境变量可能随版本变化。

官方参考:

下载并解压后进入项目目录,例如:

powershell 复制代码
cd C:\JitsiMeet\docker-jitsi-meet
Copy-Item env.example .env

生成 Jitsi 内部密码,并创建配置目录。不同版本的目录列表可能略有差异,应以对应版本的官方说明为准。

八、Jitsi 基础配置

.env 中至少配置以下内容。示例中的密码只表示配置项名称,不要把真实密码发布到博客或代码仓库。

dotenv 复制代码
PUBLIC_URL=https://<Windows局域网IP>:8443
JVB_ADVERTISE_IPS=<Windows局域网IP>
HTTPS_PORT=8443

ENABLE_AUDIO_TRANSLATION=1
ENABLE_TRANSCRIPTIONS=1
JICOFO_TRANSLATION_URL_TEMPLATE=ws://local-translation:38030/translate?sessionId={{MEETING_ID}}

# 目标语言菜单
TRANSLATION_LANGUAGES=['zh-CN','zh-TW','en','ar','ja','ko','fr','de','es','ru','it','pt','hi','th','vi','id','tr','nl']
TRANSLATION_LANGUAGES_HEAD=['zh-CN','en','ar']

# 源语言:zh、en、ja、ar 或 auto
LOCAL_SOURCE_LANGUAGE=zh

源语言是会议级设置:

  • 主要使用中文的会议设置为 zh,可以显著减少中文短句被误判成韩语、乌克兰语等语言。
  • 英语会议设置为 en
  • 语言混杂的会议设置为 auto,但短句误判概率会增加。

目标语言则是参会者级设置:B 选择英文、C 选择阿拉伯语,不会互相覆盖。

九、实现本地 Whisper/NLLB 翻译适配器

9.1 适配器的职责

local-translation 服务实现 Jitsi bridge-based transcription/translation 所需的 WebSocket 接口:

text 复制代码
/transcribe
/translate

它接收 JVB 转发的 Opus 音频,完成以下处理:

text 复制代码
Opus 音频
  → Opus 解码
  → 48 kHz 转 16 kHz
  → 简单 VAD 和静音分段
  → Faster-Whisper 识别
  → NLLB 翻译
  → transcription-result
  → JVB 转发给参会者

官方 bridge-based 转写链路也是由 JVB 通过 WebSocket 连接转写服务,再把结果注入会议。本文没有使用已经过时的 Jigasi 转写路线。

参考:Jitsi Bridge-based Transcriptions

9.2 Docker Compose 覆盖文件

本文使用单独的 translation.yml,不修改 Jitsi 官方主 Compose 文件的主体结构。关键内容如下:

yaml 复制代码
services:
  local-translation:
    build:
      context: ./local-translation
    image: jitsi/local-translation:latest
    restart: unless-stopped
    environment:
      PORT: 38030
      SOURCE_LANGUAGE: ${LOCAL_SOURCE_LANGUAGE:-auto}
      WHISPER_MODEL: small
      WHISPER_COMPUTE_TYPE: int8
      WHISPER_THREADS: 8
      TRANSLATION_MODEL_REPO: facebook/nllb-200-distilled-600M
      TRANSLATION_NUM_BEAMS: 1
      TRANSLATION_MAX_NEW_TOKENS: 96
      TRANSLATOR_DYNAMIC_INT8: 1
      SILENCE_SEC: 0.55
      MAX_UTTERANCE_SEC: 6
      MIN_SPEECH_SEC: 0.35
    volumes:
      - ./local-translation/models:/models
    networks:
      meet.jitsi:

networks:
  meet.jitsi:

服务不映射新的宿主机端口,只加入 meet.jitsi Docker 内部网络。

9.3 识别和翻译模型

本案例使用:

  • Faster-Whisper small:负责语音转文字。
  • facebook/nllb-200-distilled-600M:负责多语言文本翻译。
  • CPU 动态 INT8:减少 NLLB 内存占用和翻译耗时。

模型首次启动会下载到 local-translation/models。之后重启容器会复用缓存,但模型加载仍可能需要几十秒到几分钟。

需要注意:NLLB-200 distilled 600M 的 Hugging Face 模型卡标注为 CC-BY-NC-4.0,并且定位为研究模型。公司正式商用前必须审查模型许可证、数据合规和业务场景适用性,不能因为代码是开源的就默认模型可以直接商用。

参考:NLLB-200 distilled 600M 模型卡

十、三个关键优化

10.1 不在日志中记录字幕原文

服务端日志只保留类似下面的信息:

text 复制代码
source=zh chars=8
translation tag=<speaker-tag> target=en chars=19

不记录识别原文和译文内容;Docker 日志限制为:

yaml 复制代码
logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

注意:这只代表后端日志不保存原文。会议中的字幕仍然会在参会者浏览器中显示,浏览器端的字幕面板属于会议使用体验,不能与服务端日志混为一谈。

10.2 手动指定源语言

Whisper 在很短、音量较低或带噪声的语音上可能误判语言。已增加:

dotenv 复制代码
LOCAL_SOURCE_LANGUAGE=zh

服务也兼容 WebSocket URL 中的标准 lang 参数,例如:

text 复制代码
/translate?sessionId=<MEETING_ID>&lang=zh

对于固定语言的会议,手动指定源语言通常比自动检测更稳定。对于中英日韩等语言频繁切换的会议,再使用 auto

10.3 一次识别,多目标语言翻译

处理逻辑从:

text 复制代码
每种目标语言都重新做一次语音识别

调整为:

text 复制代码
一次 Whisper 识别
  → 共享源文本
  → 英文翻译
  → 中文翻译
  → 阿拉伯语翻译

服务端增加了识别任务和翻译任务缓存。相同音频块或相同文本/目标语言请求可以复用任务,减少重复 CPU 计算。

这并不意味着多种目标语言完全没有额外开销:每个目标语言仍需要一次文本翻译。真正进一步降低延迟,可以将 NLLB 转换为 CTranslate2/ONNX INT8,或者使用 GPU 推理。

十一、构建和启动

在部署目录执行:

powershell 复制代码
cd C:\JitsiMeet\docker-jitsi-meet

# 首次构建本地翻译镜像
docker compose -f docker-compose.yml -f translation.yml build local-translation

# 启动 Jitsi 和本地翻译服务
docker compose -f docker-compose.yml -f translation.yml up -d

# 查看服务状态
docker compose -f docker-compose.yml -f translation.yml ps

当前案例已经准备了两个 PowerShell 脚本:

powershell 复制代码
# 启动
powershell -ExecutionPolicy Bypass -File "C:\JitsiMeet\docker-jitsi-meet\start-jitsi.ps1"

# 停止,不删除配置和模型
powershell -ExecutionPolicy Bypass -File "C:\JitsiMeet\docker-jitsi-meet\stop-jitsi.ps1"

# 修改翻译代码后重新构建并启动
powershell -ExecutionPolicy Bypass -File "C:\JitsiMeet\docker-jitsi-meet\start-jitsi.ps1" -Rebuild

本案例脚本实际位于:

  • start-jitsi.ps1
  • stop-jitsi.ps1

启动脚本使用两个 Compose 文件,是因为 local-translation 和自定义 Web 镜像定义在 translation.yml 中。只执行没有 -f translation.yml 的命令,可能看不到本地翻译服务。

十二、访问和使用

在本机或同一局域网设备访问:

text 复制代码
https://<Windows局域网IP>:8443

测试阶段使用自签名证书时,浏览器会显示证书警告,需要在测试设备上手动继续访问。正式环境应使用受信任的 HTTPS 证书。

进入会议后:

  1. 允许浏览器使用麦克风和摄像头。
  2. 确认 Windows 的输入设备电平会随着说话变化。
  3. 打开字幕面板。
  4. 打开翻译语言菜单。
  5. B 选择 English,C 选择 العربية
  6. A 说中文,观察不同参会者是否看到不同语言字幕。

十三、验收清单

基础会议

  • 本机可以打开 Jitsi 页面。
  • 同一局域网内的电脑和手机可以加入。
  • 摄像头、麦克风和扬声器正常。
  • UDP 10000 可用于媒体传输。
  • 两人通话 10 分钟没有明显断流。

实时字幕翻译

  • 中文源语言设置为 zh 时,中文短句不会频繁被识别成其他语言。
  • B 选择英文后能看到英文字幕。
  • C 选择阿拉伯语后能看到阿拉伯语字幕。
  • 不同参会者的目标语言互不影响。
  • 字幕能够显示正确的说话人名称。
  • 翻译服务停止时,普通 Jitsi 音视频会议仍可以继续。
  • Docker Desktop 重启后,容器可以恢复运行。

日志和隐私

  • 服务日志中不出现识别原文和译文。
  • Docker 日志轮转已经启用。
  • 会议音频没有发送到 OpenAI 或其他云端 API。
  • 模型、配置和日志目录的访问权限已限制。

十四、常见问题

1. 页面提示 ERR_CONNECTION_REFUSED

通常检查:

powershell 复制代码
docker compose -f docker-compose.yml -f translation.yml ps
docker ps

确认 web 容器正在运行,并确认访问端口是 8443。如果 Windows 防火墙阻止了 TCP 8443,局域网设备也会无法访问。

2. 能听到对方声音,但对方听不到我

先不要从 Jitsi 服务端排查,优先检查客户端:

  • Windows 设置中的输入设备是否选择正确。
  • 麦克风音量条是否随着说话变化。
  • 浏览器网站权限是否允许麦克风。
  • Windows 隐私设置中的"允许桌面应用访问麦克风"是否打开。
  • 微信、Teams 等其他软件是否独占了麦克风。
  • Jitsi 底部麦克风按钮是否处于静音状态。

如果其他软件也采集不到声音,问题通常在 Windows 设备、驱动或麦克风本身,而不是 Jitsi。

3. 字幕延迟很高

CPU 模式下,延迟通常来自三个地方:

text 复制代码
语音分段等待 + Whisper 识别 + NLLB 翻译

可以依次尝试:

  1. 固定源语言,例如 LOCAL_SOURCE_LANGUAGE=zh
  2. 缩短 MAX_UTTERANCE_SEC,但过短会让句子被切碎。
  3. 使用更快的 Whisper 模型,但要接受识别准确率可能下降。
  4. 使用 CTranslate2/ONNX INT8 翻译。
  5. 使用 GPU 或单独的 Linux 推理服务器。

4. 字幕不准确

  • 先确认源语言设置正确。
  • 让讲话者靠近麦克风,减少回声和背景噪声。
  • 避免多人同时讲话。
  • 给专有名词、产品名和部门名增加领域词汇校正。
  • 对正式业务不要只依赖自动字幕,重要内容需要人工确认。

Whisper 官方模型卡也提醒,不同语言和不同语音条件下的识别质量并不均匀,部署前应使用自己的真实音频进行评估。

参考:Whisper 模型卡

十五、内网使用和外部使用的区别

公司内部使用

建议至少完成:

  • 使用企业 DNS,不长期依赖变化的局域网 IP。
  • 使用企业内部 CA 或受信任的 HTTPS 证书。
  • 将 Docker Desktop 测试机逐步迁移到独立 Linux 主机。
  • 配置会议密码、房间权限和主持人权限。
  • 限制管理文件、模型目录和 Docker Socket 的访问。
  • 对字幕和会议数据制定保留、清理和访问规则。
  • 评估 Whisper/NLLB 模型的许可证是否适合公司业务。
  • 对 CPU、内存、网络带宽和并发人数做压力测试。

对外部用户开放

不建议直接把当前局域网方案映射到公网。至少需要新增:

  • 公网域名。
  • 受信任的 TLS 证书。
  • 公网反向代理或正确配置的 80/443 端口。
  • JVB 的 UDP 10000 公网媒体通道。
  • 必要时配置 TURN 服务,解决复杂 NAT 和企业网络限制。
  • 身份认证、房间权限、等候室或主持人控制。
  • 防暴力尝试、限流、监控、告警和备份。
  • 独立的翻译推理节点或 GPU 节点。
  • 对外部音频、字幕、日志和模型数据进行合规评估。

外部访问时,翻译服务仍应只放在服务器内部网络,不应把 38030 直接开放给互联网。

十六、后续可以继续优化的方向

性能

  • 使用 CTranslate2 或 ONNX Runtime 的 INT8 模型。
  • 使用 GPU 推理,或者将翻译服务拆到独立 Linux 主机。
  • 进一步实现按会议共享的识别队列,减少多个 JVB 连接之间的重复识别。
  • 统计分段等待、ASR、翻译和网络发送的耗时。
  • 根据参会人数动态限制目标语言数量。

准确率

  • 使用更大的 Whisper 模型。
  • 为公司名称、产品名称、技术术语增加词汇表。
  • 使用领域翻译模型或经过评估的商用模型。
  • 增加语言置信度和低置信度提示。
  • 改善回声消除、噪声抑制和说话人分离。

产品能力

  • 在会议页面加入源语言选择,而不是只通过 .env 设置。
  • 提供字幕开关、字号、颜色和历史清理控制。
  • 增加字幕导出前的权限审批。
  • 增加翻译服务健康状态和延迟监控。
  • 在合规允许的前提下增加会议纪要和检索功能。
  • 如果需要"听到翻译后的声音",再增加 TTS 语音翻译链路;这会明显增加延迟和资源消耗。

十七、项目文件结构

最终实现中与翻译相关的文件大致如下:

text 复制代码
docker-jitsi-meet/
├─ .env
├─ docker-compose.yml
├─ translation.yml
├─ config/
│  └─ jicofo/
│     └─ custom-jicofo.conf
├─ local-translation/
│  ├─ Dockerfile
│  ├─ README.md
│  ├─ server.py
│  └─ models/
├─ web-custom/
│  └─ Dockerfile
├─ start-jitsi.ps1
└─ stop-jitsi.ps1

其中:

  • server.py:Opus 解码、VAD、Whisper、NLLB、WebSocket 协议和字幕结果。
  • translation.yml:本地翻译容器、内部网络、模型目录和日志轮转。
  • custom-jicofo.conf:将 Jicofo 的转写连接指向本地服务。
  • web-custom/Dockerfile:目标语言菜单、字幕筛选和说话人名称显示补丁。
  • .env:局域网 IP、端口、翻译开关、语言和密码配置。
  • start-jitsi.ps1 / stop-jitsi.ps1:Windows 下的一键启动和停止。

结语

这套方案证明了:在 Windows 11 上不需要原生安装 Jitsi,也可以通过 WSL2 + Docker Desktop 搭建一个可用于内网测试的 Jitsi Meet,并接入本地 Whisper/NLLB 实现实时多语言字幕。

它的核心价值是把会议、识别和翻译链路拆开:Jitsi 负责稳定的实时音视频,翻译适配器负责本地语音识别和文本翻译,参会者在前端独立选择目标语言。

但在正式投入公司或公网使用前,仍然需要重点完成三件事:

  1. 对模型许可证和数据合规进行确认。
  2. 用真实业务音频评估延迟和准确率。
  3. 将 Windows 测试机迁移到更适合长期运行的 Linux 或云服务器,并补齐认证、证书、TURN、监控和备份。
相关推荐
点亮~黑夜3 小时前
远程连接浏览无桌面服务器上的图片
windows·软件构建
Albart5753 小时前
Docker Desktop 增量更新失败终极排查:Failed to apply delta update 反复回滚怎么办?
windows·docker·容器·docker部署大模型
Patrick在香港3 小时前
Claude + Python 数据管道:一次字段改名,786 行历史数据被静默重写
开发语言·windows·python·claude·数据工程·数据校验·数据管道
Tiny2144 小时前
解决VMware中win10虚拟机无法上网
网络·windows·vmware
tryxr5 小时前
Chat2Excel 文件服务模块剩余功能开发
java·服务器·windows·java项目·文件服务
kakakahahahaha5 小时前
Windows DRIVER_IRQL_NOT_LESS_OR_EQUAL NETIO.SYS 蓝屏排查流程
windows·电脑·笔记本电脑·内容运营·软件需求
kakakahahahaha19 小时前
Windows笔记本重装系统的4种路径和风险边界
windows·电脑·笔记本电脑·内容运营·软件需求·重装系统
自动化监测Learner1 天前
Windows 自带搜索太慢?Everything 安装与使用指南,全盘文件秒搜
windows·everything
天机玄正1 天前
云运维高阶二:CLI 调用 API (白名单追随)
windows·云原生