父史诗: 史诗005 - Agora实时语音转录翻译集成 docs/prd/epic-005-agora-real-time-speech-transcription.md
Ready for Review - RTC音频发布缺失问题已修复,所有功能验证通过
High - 新功能实现,增强用户体验
As a 系统开发者 I want 集成Agora实时语音转文字完整解决方案 so that 我可以在管理后台中提供安全的语音输入转文字功能,包括前端组件和后端Token动态获取能力
RtcManager.ts,移除重复API调用,统一使用后端Token APIRtmManager.ts,移除硬编码的import.meta.env.VITE_AGORA_APP_IDcommon/request.ts中的API调用,使用后端Token API而不是直接调用Agora APIuseAgoraSTT.ts和useAgoraSTTManager.ts的功能重叠useAgoraSTT.ts中的配置获取逻辑迁移到管理器组件useAgoraSTTManager完全替代useAgoraSTT的功能useAgoraSTT.ts为废弃useAgoraSTTManager.ts,没有重复的useAgoraSTT.ts文件AgoraSTTPage页面中添加AgoraSTTProvider包裹AgoraSTTProvider包裹AgoraSTTProvider包裹useAgoraSTTManager通过useAgoraSTT获取管理器实例textstreamReceived事件监听useAgoraSTTManager.ts中替换模拟转录结果,使用真实的textstreamReceived事件onTextStreamReceived回调函数,处理ITextstream数据结构src/client/admin/components/agora-stt/managers/ (基于Agora RTT Demo架构)
RtcManager.ts - 音视频流管理RtmManager.ts - 实时消息传递SttManager.ts - 语音转文本生命周期管理src/client/admin/components/agora-stt/protobuf/
SttMessage.proto - STT消息格式定义SttMessage.js - 生成的解析器src/client/admin/components/agora-stt/ (管理后台专用组件)src/server/api/agora/ (Agora相关API路由)src/server/modules/agora/ (Agora业务逻辑模块)src/client/admin/components/agora-stt/__tests__/ 和 src/server/api/agora/__tests__/src/client/types/agora-stt.ts 和 src/server/types/agora.tssrc/client/utils/agora-stt.ts 和 src/server/utils/agora-token.ts// 前端配置 - 统一通过Token API返回,不再使用getGlobalConfig
// Token API现在同时返回Token和配置常量
const AGORA_TOKEN_ENDPOINT = '/api/v1/agora/token';
// 后端配置 - 使用环境变量安全存储
const AGORA_SERVER_CONFIG = {
appId: process.env.AGORA_APP_ID || '',
appSecret: process.env.AGORA_APP_SECRET || '',
tokenExpiry: parseInt(process.env.AGORA_TOKEN_EXPIRY || '3600'),
primaryCert: process.env.AGORA_PRIMARY_CERT || '',
sttJoinUrl: process.env.AGORA_STT_JOIN_URL || 'https://api.agora.io/v7/rtm/stt/join',
sttWsUrl: process.env.AGORA_STT_WS_URL || 'wss://api.agora.io/v7/rtm/stt/connect',
defaultChannel: process.env.AGORA_DEFAULT_CHANNEL || '123'
};
message Text {
int32 vendor = 1; // 供应商标识
int32 version = 2; // 协议版本
int64 uid = 4; // 用户ID
string data_type = 13; // 数据类型: transcribe/translate
repeated Word words = 10; // 词汇列表
repeated Translation trans = 14; // 翻译结果
string culture = 15; // 语言文化标识
int64 text_ts = 16; // 文本时间戳
}
message Word {
string text = 1; // 词汇文本
int32 start_ms = 2; // 开始时间(毫秒)
bool is_final = 4; // 是否为最终结果
double confidence = 5; // 置信度
}
message Translation {
bool is_final = 1; // 是否为最终翻译
string lang = 2; // 目标语言
repeated string texts = 3; // 翻译文本
}
tests/e2e/specs/admin/agora-stt.spec.tssrc/server/api/agora/__tests__/agora-token.integration.test.ts采用Agora RTT Demo的三管理器架构:
// src/client/admin/components/agora-stt/managers/RtcManager.ts
export class RtcManager extends AGEventEmitter<RtcEvents> {
// 音视频流管理,处理音频采集和WebRTC传输
}
// src/client/admin/components/agora-stt/managers/RtmManager.ts
export class RtmManager extends AGEventEmitter<RtmEvents> {
// 实时消息传递,处理分布式锁和会话状态
async acquireLock(): Promise<void> { /* 获取分布式锁 */ }
async releaseLock(): Promise<void> { /* 释放分布式锁 */ }
}
// src/client/admin/components/agora-stt/managers/SttManager.ts
export class SttManager extends AGEventEmitter<STTEvents> {
// 语音转文本生命周期管理
async startTranscription(options: STTManagerStartOptions): Promise<void> {
// 获取分布式锁
await this.rtmManager.acquireLock();
// 获取Token和配置
const { token, config } = await fetchAgoraConfigAndToken('rtc');
// 启动转录任务
const res = await apiSTTStartTranscription({
uid: this.userId,
channel: this.channel,
languages: options.languages,
token,
});
}
}
// src/client/admin/components/agora-stt/protobuf/parser.ts
export class Parser extends AGEventEmitter<ParserEvents> {
praseData(data: any) {
const textstream = protoRoot.Agora.SpeechToText.lookup("Text").decode(data);
if (!textstream) {
return console.warn("Prase data failed.");
}
this.emit("textstreamReceived", textstream);
}
}
// 基于Agora RTT Demo的字幕处理逻辑
case "transcribe": {
let textStr: string = ""
let isFinal = false
words.forEach((word: any) => {
textStr += word.text
if (word.isFinal) {
isFinal = true
}
})
// 查找未完成的字幕记录,支持增量更新
const st = state.sttSubtitles.findLast((el) => {
return el.uid == textstream.uid && !el.isFinal
})
// 更新或创建字幕记录
}
// 使用项目现有的API客户端配置获取Token和配置
import { hc } from 'hono/client';
import type { AgoraRoutes } from '@/server/api';
const fetchAgoraConfigAndToken = async (type: 'rtc' | 'rtm', channel?: string, userId?: string) => {
const response = await agoraClient.token.$get({
query: { type, channel, userId }
});
if (!response.ok) {
throw new Error('Token和配置获取失败');
}
const data = await response.json();
return {
token: data.data.token,
config: {
appId: data.data.appId,
sttJoinUrl: data.data.sttJoinUrl,
sttWsUrl: data.data.sttWsUrl,
defaultChannel: data.data.defaultChannel
}
};
};
tests/e2e/specs/admin/agora-stt.spec.tssrc/server/api/agora/__tests__/agora-token.integration.test.ts// 集成测试示例:验证Token API返回配置常量
test('Token API返回配置常量', async () => {
const response = await client.agora.token.$get({
query: { type: 'rtc', channel: 'test-channel' }
});
expect(response.status).toBe(200);
const data = await response.json();
// 验证Token信息
expect(data).toHaveProperty('token');
expect(data).toHaveProperty('type');
expect(data).toHaveProperty('expiresAt');
expect(data).toHaveProperty('expiresIn');
expect(data).toHaveProperty('generatedAt');
// 验证配置常量字段
expect(data).toHaveProperty('appId');
expect(data).toHaveProperty('sttJoinUrl');
expect(data).toHaveProperty('sttWsUrl');
expect(data).toHaveProperty('defaultChannel');
// 验证配置常量值与后端环境变量一致
expect(data.appId).toBe(process.env.AGORA_APP_ID || '');
expect(data.sttJoinUrl).toBe(process.env.AGORA_STT_JOIN_URL || 'https://api.agora.io/v7/rtm/stt/join');
expect(data.sttWsUrl).toBe(process.env.AGORA_STT_WS_URL || 'wss://api.agora.io/v7/rtm/stt/connect');
expect(data.defaultChannel).toBe(process.env.AGORA_DEFAULT_CHANNEL || '123');
});
| Date | Version | Description | Author |
|---|---|---|---|
| 2025-09-23 | 1.0 | 初始故事创建 | John (PM) |
| 2025-09-23 | 1.1 | 安全配置修复:环境变量替代硬编码 | Bob (SM) |
| 2025-09-23 | 1.1 | 目录结构对齐:组件位置修正 | Bob (SM) |
| 2025-09-23 | 1.1 | 添加安全考虑章节 | Bob (SM) |
| 2025-09-23 | 1.2 | 整合前端规范文档,添加UX设计要求 | Bob (SM) |
| 2025-09-23 | 1.3 | 组件实现验证和代码修复,状态更新为Ready for Review | James (Dev) |
| 2025-09-23 | 1.4 | 发现缺少E2E测试文件,状态回退为In Development | Bob (SM) |
| 2025-09-23 | 1.5 | 补充Token动态获取后端路由和前端集成需求 | Bob (SM) |
| 2025-09-23 | 1.6 | 优化:Agora前端常量统一通过Token API返回,便于调试和统一管理 | Bob (SM) |
| 2025-09-23 | 1.7 | 架构改进:基于Agora RTT Demo实现方式,集成管理器架构和Protocol Buffer | Bob (SM) |
| 2025-09-24 | 1.8 | 状态检查:发现前端配置获取不一致和钩子重复问题,状态保持为In Development | Bob (SM) |
| 2025-09-24 | 1.9 | E2E测试修复:修复Agora STT端到端测试,15个测试通过,1个跳过 | Claude Code |
| 2025-09-24 | 2.0 | 转录结果监听分析:发现当前项目使用模拟数据而非真实事件监听,基于Agora RTT Demo添加迁移任务 | Bob (SM) |
| 2025-09-24 | 2.1 | 状态检查更新:确认Provider问题已修复,钩子无重复,配置获取部分统一,转录结果监听待实现 | Bob (SM) |
| 2025-09-24 | 2.2 | 配置统一修复:修复RtcManager中的重复API调用问题,统一配置获取方式 | Claude Code |
| 2025-09-24 | 2.3 | 真实转录结果监听实现:在AgoraSTTProvider中实现真实的事件监听机制,替换模拟数据 | James (Dev) |
| 2025-09-24 | 2.4 | 纠正路线任务:发现RTC音频发布缺失问题,状态调整为In Development,添加修复任务 | Bob (SM) |
| 2025-09-24 | 2.5 | RTC音频发布修复:修复STT管理器中的RTC join调用和音频轨道发布缺失问题,状态更新为Ready for Review | James (Dev) |
useAgoraSTTManager.ts,没有重复的useAgoraSTT.ts文件AgoraSTTPage页面正确使用AgoraSTTProvider包裹,测试文件也正确使用Provider。架构确认:组件正确使用Provider模式textstreamReceived事件监听机制,替换了模拟数据AgoraSTTProvider中实现,通过Provider提供管理器实例和事件监听common/request.ts中已实现统一的配置获取函数,RtcManager中已统一使用后端Token APIsrc/client/admin/components/agora-stt/AgoraSTTProvider.tsx - 主Provider组件,已实现真实的事件监听机制src/client/admin/components/agora-stt/hooks/useAgoraSTTManager.ts - 管理器钩子,已替换模拟数据为真实转录结果src/client/admin/components/agora-stt/manager/parser/types.ts - Protocol Buffer类型定义,已更新匹配实际数据结构src/client/admin/components/agora-stt/manager/stt/stt.ts - STT管理器,已添加RTC join调用和音频轨道管理src/client/admin/components/agora-stt/manager/stt/types.ts - STT管理器类型定义,已添加RTC管理器参数src/client/admin/components/agora-stt/manager/rtc/rtc.ts - RTC管理器,已优化音频轨道创建和发布src/client/admin/components/agora-stt/manager/rtc/types.ts - RTC管理器类型定义,已更新音频轨道接口src/client/admin/components/agora-stt/manager/rtc/rtc.ts - 音视频流管理,已包含真实的事件监听src/client/admin/components/agora-stt/manager/rtm/rtm.ts - 实时消息传递src/client/admin/components/agora-stt/manager/stt/stt.ts - 语音转文本生命周期管理src/client/admin/components/agora-stt/manager/parser/parser.ts - Protocol Buffer解析器src/client/admin/components/agora-stt/protobuf/SttMessage.proto - STT消息格式定义src/client/admin/components/agora-stt/protobuf/SttMessage.js - 生成的解析器src/client/admin/components/agora-stt/__tests__/AgoraSTTComponent.test.tsx - 组件单元测试src/client/admin/components/agora-stt/__integration_tests__/AgoraSTTComponent.integration.test.tsx - 集成测试tests/e2e/specs/admin/agora-stt.spec.ts - E2E测试src/server/api/agora/token/get.ts - Token生成路由(待创建)src/server/modules/agora/agora-token.service.ts - Token生成服务(待创建)src/server/types/agora.ts - 后端类型定义(待创建)src/server/api/agora/__tests__/agora-token.integration.test.ts - Token路由集成测试(待创建)src/server/api/index.ts - 需要导出AgoraRoutes类型(需要更新)src/client/api.ts - 需要添加Agora客户端导出(需要更新)tests/e2e/specs/admin/agora-stt.spec.ts - E2E测试文件(待创建)src/client/admin/components/agora-stt/managers/__tests__/ - 管理器单元测试(待创建)src/client/admin/components/agora-stt/protobuf/__tests__/ - Protocol Buffer解析测试(待创建)tests/e2e/specs/admin/agora-stt.spec.ts定位器问题修复
data-testid属性agora-stt.page.ts、AgoraSTTComponent.tsx测试环境适配
错误处理优化
无障碍功能修复
代码质量改进
E2E测试部分: Ready for Review 整体故事: In Development(其他问题待解决)