实时字幕

更新时间不可用

本文介绍如何在你的 App 中实现实时字幕功能。

与对话式智能体进行实时互动时,你可能需要实时字幕来显示你与智能体的对话内容。本文介绍如何在你的 App 中实现实时字幕功能。

技术原理

声网提供一套灵活可扩展、标准化的对话式 AI 引擎客户端组件(以下简称组件)。该组件支持 iOS、Android、Web 平台,封装了多个场景化 API,你只需要调用这些 API 即可结合声网实时互动 (RTC) SDK 和实时消息 (RTM) SDK 的能力实现以下功能:

组件通过 onTranscriptUpdated 回调接收字幕转录内容,支持监听不同类型的字幕转录信息:

  • 智能体字幕:智能体的语音转录内容,包括实时更新和最终结果。
  • 用户字幕:用户的语音转录内容,支持实时显示和状态管理。
  • 字幕转录状态:支持进行中、完成、中断等不同状态的处理。

以下为使用组件实现实时字幕功能的工作流程图:

前提条件

开始前,请确保完成以下准备工作:

  • 已集成 RTC v4.5.1 及以上版本 SDK,且在 App 中实现了基本的实时音视频功能、获取了相关设备的使用权限。请参考实现音视频互动。
  • 已在控制台为项目启用 RTM 服务,并在 App 中实现了基本的实时消息功能。请参考实现收发消息。
  • 已参考实现对话式智能体实现与智能体对话的基本逻辑。
  • 确保 RTC 可用、RTM 已登录,且 RTC 和 RTM 实例的生命周期大于组件的生命周期。组件内部不负责维护 RTC,RTM 的初始化、生命周期以及鉴权/登录状态的逻辑。
  • 已集成 RTC v4.5.1 及以上版本 SDK,且在 App 中实现了基本的实时音视频功能、获取了相关设备的使用权限。请参考实现音视频互动。
  • 已在控制台为项目启用 RTM 服务,并在 App 中实现了基本的实时消息功能。请参考实现收发消息。
  • 已参考实现对话式智能体实现与智能体对话的基本逻辑。
  • 确保 RTC 可用、RTM 已登录,且 RTC 和 RTM 实例的生命周期大于组件的生命周期。组件内部不负责维护 RTC,RTM 的初始化、生命周期以及鉴权/登录状态的逻辑。
  • 已集成 v4.24.0 及以上版本的 RTC Web SDK,并参考实现音视频互动在 App 中实现了基本的实时音视频功能、获取了相关设备的使用权限。
  • 已在控制台为项目启用 RTM 服务,并在 App 中实现了基本的实时消息功能。请参考实现收发消息。
  • 已参考实现对话式智能体实现与智能体对话的基本逻辑。
  • 确保 RTC 可用、RTM 已登录,且 RTC 和 RTM 实例的生命周期大于组件的生命周期。组件内部不负责维护 RTC,RTM 的初始化、生命周期以及鉴权/登录状态的逻辑。

实现方法

集成组件

Maven (Maven)

在 Android 项目的 build.gradle 文件中添加如下依赖:

Text
implementation 'io.agora.agents:agora-agent-client-toolkit:2.10.0'

源码集成 (源码集成)

将 convoaiApi 文件夹拷贝到你的项目中,并在后续调用组件 API 前引入组件。你可以前往组件结构了解各个文件作用。

CocoaPods (CocoaPods)

在 Podfile 中添加如下依赖:

Ruby
pod 'agent-client-toolkit-swift', '2.10.0'

Swift Package Manager (Swift Package Manager)

在 Xcode 中添加如下 Package URL,并将版本指定为 tag 2.10.0:

Text
https://github.com/AgoraIO/agent-client-toolkit-swift.git

源码集成 (源码集成)

将 ConversationalAIAPI 文件夹拷贝到你的项目中,并在后续调用组件 API 前引入组件。你可以前往组件结构了解各个文件作用。

Package Manager (Package Manager)

根据你的项目类型安装组件依赖。

  • Vanilla JS / TypeScript:

    Bash
    pnpm add agora-agent-client-toolkit@2.10.0
  • React:

    Bash
    pnpm add agora-agent-client-toolkit@2.10.0 agora-agent-client-toolkit-react@2.10.0

源码集成 (源码集成)

将 conversational-ai-api 文件拷贝到你的项目中,并在后续调用组件 API 前引入组件。你可以前往组件结构了解各个文件作用。

初始化组件

为 RTC 和 RTM 实例创建配置对象,并设置转录字幕渲染模式,之后创建组件实例:

Kotlin
// 为 RTC 和 RTM 实例创建配置对象
val config = ConversationalAIAPIConfig(
    rtcEngine = rtcEngineInstance,
    rtmClient = rtmClientInstance,
    /**
     * 设置转录字幕渲染模式,可选值:
     * - `TranscriptRenderMode.Word`:逐字渲染模式,即回调接收的字幕内容将逐字渲染到 UI 上。
     * - `TranscriptRenderMode.Text`:逐句渲染模式,即回调接收的字幕内容将全量渲染到 UI 上。
     */
    renderMode = TranscriptRenderMode.Word,
    enableLog = true
)
// 创建组件实例
val api = ConversationalAIAPIImpl(config)
Swift
/// 为 RTC 和 RTM 实例创建配置对象
let config = ConversationalAIAPIConfig(
    rtcEngine: rtcEngine, 
    rtmEngine: rtmEngine,
    /**
     * 设置转录字幕渲染模式,可选值:
     * - `.words`:逐字渲染模式,即回调接收的字幕内容将逐字渲染到 UI 上。
     * - `.text`:逐句渲染模式,即回调接收的字幕内容将全量渲染到 UI 上。
     */
    renderMode: .words, 
    enableLog: true
)
/// 创建组件实例
convoAIAPI = ConversationalAIAPIImpl(config: config)
TypeScript
// 初始化组件
ConversationalAIAPI.init({
    rtcEngine,
    rtmEngine,
/**
 * 设置转录字幕渲染模式,可选值:
 * - `ESubtitleHelperMode.WORD`:逐字渲染模式,即回调接收的字幕内容将逐字渲染到 UI 上。
 * - `ESubtitleHelperMode.TEXT`:逐句渲染模式,即回调接收的字幕内容将全量渲染到 UI 上。
 * 
 * 不指定则自动根据消息判断模式,或手动指定模式
 */
    renderMode: ESubtitleHelperMode.WORD, 
    })

// 获取 API 实例(单例)
const conversationalAIAPI = ConversationalAIAPI.getInstance()

信息

逐字渲染模式 (ESubtitleHelperMode.WORD) 下需要接收来自 RTC 的音频时间戳信息才能实现字幕和语音同步输出。为此,在创建客户端对象前,请确保完成以下设置:

TypeScript
// 设置传递音频时间戳信息
AgoraRTC.setParameter("ENABLE_AUDIO_PTS_METADATA", true);
// 创建客户端对象并指定频道场景和浏览器编码方式
const client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });

注册字幕回调

调用 addHandler 方法,注册并实现字幕转录回调:

Kotlin
api.addHandler(covEventHandler)
Swift
convoAIAPI.addHandler(handler: self)
TypeScript
// 监听转录内容更新,用于实时显示字幕转录内容
conversationalAIAPI.on(EConversationalAIAPIEvents.TRANSCRIPT_UPDATED, onTextChanged)

实现字幕数据回调接口

你需要自行实现字幕处理逻辑,根据转录内容更新 UI 显示。

将你实现的字幕 UI 模块继承自 IConversationalAIAPIEventHandler 接口,并实现 onTranscriptUpdated 方法,在该方法内处理字幕渲染至 UI 的逻辑。

Kotlin
 private val covEventHandler = object : IConversationalAIAPIEventHandler {
   override fun onTranscriptUpdated(agentUserId: String, transcript: Transcript) {
        // 在此处接收字幕更新 UI
    }      
}

将你实现的字幕 UI 模块实现 ConversationalAIAPIEventHandler 协议,并实现 onTranscriptUpdated 方法,在该方法内处理字幕渲染至 UI 的逻辑:

Swift
extension ChatViewController: ConversationalAIAPIEventHandler {
    public func onTranscriptUpdated(agentUserId: String, transcript: Transcript) {
        //可以在此处接收字幕更新 UI
    }
}

将你实现的字幕 UI 模块接收客户端组件的字幕数据回调,并实现一个简单的 React JS 组件来展示这些消息:

信息

  • 所有 TRANSCRIPT_UPDATED 事件回调均返回完整聊天对话列表。每次均有可能更新最近的几条对话字幕,请根据完整的列表渲染 UI。
  • 推荐使用状态管理库如 zustand、redux 等来代替 React.useState 管理状态,以便在组件间共享状态。
TSX
import * as React from "react"
import {
  type IUserTranscript,
  type IAgentTranscript,
  type ISubtitleHelperItem,
  EConversationalAIAPIEvents,
} from "@/conversational-ai-api/type"
import { ConversationalAIAPI } from "@/conversational-ai-api"

// 监听转录内容更新,用于实时显示字幕转录内容
export const ChatHistory = () => {
  const [chatHistory, setChatHistory] = React.useState<
    ISubtitleHelperItem<Partial<IUserTranscript | IAgentTranscript>>[]
  >([])

  const conversationalAIAPI = ConversationalAIAPI.getInstance()
  conversationalAIAPI.on(
    EConversationalAIAPIEvents.TRANSCRIPT_UPDATED,
    setChatHistory
  )

  return (
    <>
      {chatHistory.map((message) => (
        <div key={`${message.uid}-${message.turn_id}`}>
          {message.uid}: {message.text}
        </div>
      ))}
    </>
  )
}

订阅频道消息

字幕转录内容通过 RTM 频道消息传递,你需要在开始智能体会话前订阅频道消息,以接收字幕数据。

在开始智能体会话前调用 subscribeMessage 订阅频道消息:

Kotlin
api.subscribeMessage("channelName") { error ->
    if (error != null) {
        // 处理错误
    }
}

在开始智能体会话前调用 subscribeMessage 订阅频道消息:

Swift
convoAIAPI.subscribeMessage(channelName: channelName) { error in
    if let error = error {
        print("订阅失败: \(error.message)")
    } else {
        print("订阅成功")
    }
}
TypeScript
conversationalAIAPI.subscribeMessage(channel_name)

智能体加入频道

你可以通过 RESTful API 或 Agents SDK 创建并启动智能体;本文后续步骤聚焦客户端组件侧的事件订阅和消息处理。

调用 POST 创建对话式智能体接口,或在 Agents SDK 的会话配置中完成以下参数设置:

  • advanced_features.enable_rtm: true —— (必选)启动 RTM 服务
  • parameters.data_channel: "rtm" —— (必选)开启 RTM 数据传输通道
  • parameters.enable_metrics: true —— (按需开启)接收智能体性能数据
  • parameters.enable_error_message: true —— (按需开启)接收智能体错误事件

调用成功后,智能体会加入指定 RTC 频道,用户可以开始与智能体互动。

取消订阅频道消息

每次智能体会话结束后,你需要取消订阅频道消息,以释放字幕相关资源。

Kotlin
api.unsubscribeMessage("channelName") { error ->
    if (error != null) {
        // 处理错误
    }
}
Swift
/// 取消订阅频道消息
convoAIAPI.unsubscribeMessage(channelName: channelName) { error in
    if let error = error {
        print("取消订阅失败: \(error.message)")
    } else {
        print("取消订阅成功")
    }
}
TypeScript
conversationalAIAPI.unsubscribeMessage(channel_name)

销毁组件实例

结束 AI 对话场景后或关闭 App 前,你需要销毁组件实例,以释放组件的所有资源。

Kotlin
api.destroy()
Swift
convoAIAPI.destroy()
TypeScript
conversationalAIAPI.destroy()

参考信息

示例项目

声网提供了开源的实时字幕示例项目供你参考,你可以前往下载或查看其中的源代码。

组件结构

客户端组件文件夹的结构和各文件作用如下:

信息

以下文件和文件夹即为集成客户端组件所需全部内容,无需拷贝其他文件。

  • IConversationalAIAPI.kt — API 接口及相关数据结构和枚举
  • ConversationalAIAPIImpl.kt — ConversationalAI API 主要实现逻辑
  • ConversationalAIUtils.kt — 工具函数与事件回调管理
  • subRender/
    • v3/ — 字幕部分模块
      • TranscriptionController.kt — 字幕控制器
      • MessageParser.kt — 消息解析器
  • ConversationalAIAPI.swift — API 接口
  • ConversationalAIAPIImpl.swift — ConversationalAI API 主要实现逻辑
  • MessageModels.swift — 消息模型和相关枚举
  • MessagePayloadBuilder.swift — RTM 消息载荷构造器
  • Transcription/
    • TranscriptionController.swift — 字幕控制器
  • index.ts — API 类
  • type.ts — API 接口及相关数据结构和枚举
  • utils/index.ts — API 工具函数
  • utils/events.ts — 事件管理类,可以拓展该类以轻松实现事件监听和播报
  • utils/sub-render.ts — 字幕部分模块

API 参考