95 lines
6.0 KiB
Markdown
95 lines
6.0 KiB
Markdown
# 系统架构
|
||
|
||
本项目是一个基于 FunASR 和 FastAPI 构建的高性能、实时的语音识别(ASR)WebSocket 服务。其核心架构设计旨在处理实时的流式音频数据,并通过 "一发多收" 的广播模式,将识别结果分发给多个客户端。
|
||
|
||
## 核心组件
|
||
|
||
系统主要由以下几个核心组件构成,它们各司其职,通过异步和多线程协作,实现了高效的实时语音处理:
|
||
|
||
1. **WebSocket 服务 (FastAPI)**
|
||
- **文件**: `src/websockets/`, `src/server.py`, `main.py`
|
||
- **职责**: 作为系统的网络入口,负责处理 WebSocket 连接。它使用 FastAPI 构建,提供异步的、非阻塞的 I/O 处理能力,能够高效地管理大量并发客户端连接。`asr_endpoint.py` 是核心端点,负责根据客户端声明的 `mode` (sender/receiver) 将连接路由到 `ASRRunner`。
|
||
|
||
2. **会话管理器 (ASRRunner)**
|
||
- **文件**: `src/runner/ASRRunner.py`
|
||
- **职责**: 这是整个系统的"大脑"和协调中心。它管理所有活跃的语音识别会话(`SenderAndReceiver`,简称 SAR)。
|
||
- **会话生命周期**: 当一个 `sender` 连接时,`ASRRunner` 会创建一个新的 SAR 实例;当 `receiver` 连接时,会将其加入到指定的 SAR 中。
|
||
- **异步桥梁**: `ASRRunner` 运行在主 `asyncio` 事件循环中,负责从 `sender` 的 WebSocket 连接异步接收音频数据,然后通过线程安全的队列 (`queue.Queue`) 将数据传递给同步的 `ASRPipeline`。同时,它也负责接收来自 Pipeline 的最终结果,并将其异步广播给所有 `receiver`。
|
||
|
||
3. **语音处理流水线 (ASRPipeline)**
|
||
- **文件**: `src/pipeline/ASRpipeline.py`
|
||
- **职责**: 这是实际执行语音处理任务的核心引擎。每个 SAR 会话都拥有一个独立的 `ASRPipeline` 实例,该实例在自己的后台线程中运行。
|
||
- **模块化设计**: Pipeline 内部由多个 `Functor` (如 VAD, ASR, SPK) 组成,通过一系列内部队列连接,形成一个处理链。
|
||
- **处理流程**:
|
||
1. **VAD (Voice Activity Detection)**: 检测音频流中的有效语音片段。
|
||
2. **ASR (Automatic Speech Recognition)**: 将语音片段转换为文字。
|
||
3. **SPK (Speaker Recognition)**: 识别说话人(声纹识别)。
|
||
4. **ResultBinder**: 将 ASR 的文本结果和 SPK 的说话人结果合并,生成最终的识别消息。
|
||
|
||
4. **原子操作单元 (Functor)**
|
||
- **文件**: `src/functor/`
|
||
- **职责**: `Functor` 是 Pipeline 中执行具体原子任务的单元。每个 Functor 都是一个独立的类,负责调用底层 FunASR 模型来执行 VAD、ASR 或 SPK 等任务。这种设计使得处理流程更加清晰和模块化。
|
||
|
||
## 流程图
|
||
|
||
下面是系统处理一次完整语音识别请求的流程图,展示了从客户端连接到收到识别结果的全过程。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Sender Client
|
||
participant Receiver Client
|
||
participant FastAPI WebSocket Endpoint
|
||
participant ASRRunner
|
||
participant ASRPipeline (Thread)
|
||
participant Functors (VAD, ASR, SPK)
|
||
|
||
par
|
||
Sender Client->>+FastAPI WebSocket Endpoint: 发起连接 (mode=sender, session_id=S1)
|
||
FastAPI WebSocket Endpoint->>+ASRRunner: new_SAR(ws, name="S1")
|
||
ASRRunner->>ASRRunner: 创建 SenderAndReceiver (SAR) 实例
|
||
ASRRunner->>ASRPipeline (Thread): 创建并运行 Pipeline 实例
|
||
ASRPipeline (Thread)->>Functors (VAD, ASR, SPK): 初始化 Functor 线程
|
||
ASRRunner->>-FastAPI WebSocket Endpoint: 返回成功
|
||
FastAPI WebSocket Endpoint->>-Sender Client: 连接建立
|
||
and
|
||
Receiver Client->>+FastAPI WebSocket Endpoint: 发起连接 (mode=receiver, session_id=S1)
|
||
FastAPI WebSocket Endpoint->>+ASRRunner: join_SAR(ws, name="S1")
|
||
ASRRunner->>ASRRunner: 将 Receiver 加入 S1 的接收者列表
|
||
ASRRunner->>-FastAPI WebSocket Endpoint: 返回成功
|
||
FastAPI WebSocket Endpoint->>-Receiver Client: 连接建立
|
||
end
|
||
|
||
loop 音频流传输与处理
|
||
Sender Client->>ASRRunner: 发送音频数据块
|
||
ASRRunner->>ASRPipeline (Thread): (via Queue) 传递音频数据
|
||
ASRPipeline (Thread)->>Functors (VAD, ASR, SPK): (via sub-queues) 分发数据
|
||
Note over Functors (VAD, ASR, SPK): 1. VAD检测语音<br/>2. ASR识别文本<br/>3. SPK识别说话人<br/>4. ResultBinder合并结果
|
||
Functors (VAD, ASR, SPK)->>ASRPipeline (Thread): (via callback) 返回最终识别结果
|
||
ASRPipeline (Thread)->>ASRRunner: (via thread-safe callback) 发送结果
|
||
end
|
||
|
||
ASRRunner->>ASRRunner: 收到结果,准备广播
|
||
ASRRunner-->>Sender Client: 广播识别结果
|
||
ASRRunner-->>Receiver Client: 广播识别结果
|
||
|
||
par
|
||
Sender Client->>FastAPI WebSocket Endpoint: 关闭连接
|
||
FastAPI WebSocket Endpoint->>ASRRunner: (触发异常)
|
||
ASRRunner->>ASRPipeline (Thread): 发送停止信号
|
||
ASRPipeline (Thread)->>Functors (VAD, ASR, SPK): 停止 Functor 线程
|
||
Note right of ASRRunner: 清理会话资源
|
||
and
|
||
Receiver Client->>FastAPI WebSocket Endpoint: 关闭连接
|
||
FastAPI WebSocket Endpoint->>ASRRunner: (触发异常)
|
||
ASRRunner->>ASRRunner: 从接收者列表移除
|
||
end
|
||
|
||
```
|
||
|
||
## 架构优势
|
||
|
||
- **高并发和低延迟**: 采用 `asyncio` 和 WebSocket,网络层能够处理大量并发连接。音频处理在独立的线程中进行,避免了 CPU 密集型任务阻塞事件循环,保证了低延迟。
|
||
- **解耦与模块化**: `WebSocket Endpoint`、`ASRRunner` 和 `ASRPipeline` 职责清晰,相互解耦。`Functor` 的设计使得添加或修改处理步骤变得容易。
|
||
- **鲁棒性**: 每个识别会话(SAR)都是隔离的,一个会话的失败不会影响其他会话。优雅的关闭逻辑确保了资源的正确释放。
|
||
- **可扩展性**: "一发多收" 的广播模式可以轻松扩展到大量 `receiver`,适用于多种实时应用场景。
|