mstf-kit
Version:
一个现代化的 JavaScript/TypeScript 工具库,提供了丰富的常用工具函数
540 lines (417 loc) • 13.8 kB
Markdown
# 非流式音频处理工具使用指南
## 概述
`audioNonStream` 模块提供了一套完整的工具函数,用于处理非流式接口返回的音频数据。支持多种数据格式(Base64、Blob、ArrayBuffer、File)和灵活的字段路径提取。
## 主要特性
- ✅ 支持多种数据格式:Base64、Blob、ArrayBuffer、File
- ✅ 灵活的字段路径提取:支持嵌套路径(如 `data.audio` 或 `result.voice.content`)
- ✅ 自动类型检测:无需手动指定数据类型
- ✅ 自动播放功能:可选的音频自动播放
- ✅ 批量处理:支持批量处理多个音频响应
- ✅ 完整的回调系统:onAudioData、onError、onComplete
- ✅ TypeScript 支持:完整的类型定义
- ✅ 调试模式:可选的详细日志输出
## 安装
```bash
npm install mstf-kit
```
## 基本使用
### 1. 处理嵌套字段的 Base64 数据
```typescript
import { processNonStreamAudio } from 'mstf-kit';
// 服务器返回格式:
// {
// "msg": "success",
// "code": 200,
// "data": {
// "audio": "UklGRiQAAABXQVZFZm10..." // Base64音频数据
// }
// }
const response = await fetch('/api/audio');
const data = await response.json();
const result = await processNonStreamAudio(data, {
audioField: 'data.audio', // 指定音频数据的路径
dataType: 'base64', // 指定数据类型
mimeType: 'audio/wav', // 指定MIME类型
autoPlay: true // 自动播放
});
console.log('音频URL:', result.url);
console.log('音频大小:', result.size);
console.log('音频类型:', result.mimeType);
// 使用音频URL
const audioElement = document.querySelector('audio');
audioElement.src = result.url;
```
### 2. 处理直接字段的 Base64 数据
```typescript
// 服务器返回格式:
// {
// "msg": "success",
// "audio": "UklGRiQAAABXQVZFZm10..." // Base64音频数据
// }
const result = await processNonStreamAudio(response, {
audioField: 'audio', // 直接指定字段名
autoPlay: true
});
```
### 3. 自动检测数据类型
```typescript
// 不指定 dataType,工具会自动检测
const result = await processNonStreamAudio(response, {
audioField: 'data.audio'
// dataType 会自动检测为 'base64'
});
```
### 4. 处理 ArrayBuffer 响应
```typescript
import axios from 'axios';
// 使用 axios 获取 ArrayBuffer
const response = await axios.get('/api/audio', {
responseType: 'arraybuffer'
});
const result = await processNonStreamAudio(response.data, {
dataType: 'arraybuffer',
mimeType: 'audio/mp3'
});
```
### 5. 处理 Blob 响应
```typescript
// 使用 fetch 获取 Blob
const response = await fetch('/api/audio');
const blob = await response.blob();
const result = await processNonStreamAudio(blob, {
dataType: 'blob'
});
```
### 6. 处理 File 对象
```typescript
// 从文件上传获取 File 对象
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];
const result = await processNonStreamAudio(file, {
dataType: 'file',
mimeType: 'audio/mp3'
});
```
## 高级用法
### 使用回调函数
```typescript
const result = await processNonStreamAudio(response, {
audioField: 'data.audio',
dataType: 'base64',
// 音频数据回调
onAudioData: (blob) => {
console.log('收到音频数据:', blob.size, '字节');
// 可以在这里更新UI,显示音频信息
},
// 错误回调
onError: (error) => {
console.error('处理音频失败:', error);
// 显示错误提示
alert('音频加载失败,请重试');
},
// 完成回调
onComplete: (blob) => {
console.log('处理完成');
if (blob) {
console.log('成功获取音频,大小:', blob.size);
}
}
});
```
### 启用调试模式
```typescript
const result = await processNonStreamAudio(response, {
audioField: 'data.audio',
debug: true // 启用详细日志输出
});
// 控制台会输出详细的处理过程:
// [NonStreamAudio] 开始处理非流式音频响应 {...}
// [NonStreamAudio] 按字段路径提取音频数据: data.audio
// [NonStreamAudio] 从response.data中提取数据
// [NonStreamAudio] 提取的音频数据类型: string
// [NonStreamAudio] 自动检测的数据类型: base64
// [NonStreamAudio] 将Base64数据转换为Blob
// [NonStreamAudio] 成功创建Blob: { size: 12345, type: 'audio/mpeg' }
// ...
```
### 批量处理多个音频
```typescript
import { processBatchNonStreamAudio } from 'mstf-kit';
const responses = [
{ data: { audio: "base64data1..." } },
{ data: { audio: "base64data2..." } },
{ data: { audio: "base64data3..." } }
];
const results = await processBatchNonStreamAudio(responses, {
audioField: 'data.audio',
dataType: 'base64',
mimeType: 'audio/wav'
});
// 遍历结果
results.forEach((result, index) => {
console.log(`音频${index + 1}:`, {
url: result.url,
size: result.size,
type: result.mimeType
});
// 创建播放列表
const audioElement = document.createElement('audio');
audioElement.src = result.url;
audioElement.controls = true;
document.body.appendChild(audioElement);
});
```
## 便捷函数
### 快速获取 Blob
```typescript
import { getAudioBlob } from 'mstf-kit';
// 快速提取音频 Blob,无需其他信息
const blob = await getAudioBlob(response, 'data.audio', 'base64');
// 使用 Blob
const url = URL.createObjectURL(blob);
audioElement.src = url;
```
### 快速创建音频 URL
```typescript
import { createAudioUrl } from 'mstf-kit';
// 直接获取可用的音频 URL
const url = await createAudioUrl(response, {
audioField: 'data.audio',
dataType: 'base64'
});
audioElement.src = url;
```
### 下载音频文件
```typescript
import { downloadAudio } from 'mstf-kit';
// 触发浏览器下载音频文件
await downloadAudio(response, 'my-audio.mp3', {
audioField: 'data.audio',
dataType: 'base64'
});
```
## 实际应用场景
### 场景1:TTS(文本转语音)服务
```typescript
import { processNonStreamAudio } from 'mstf-kit';
async function textToSpeech(text: string) {
try {
// 调用TTS API
const response = await fetch('/api/tts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text })
});
const data = await response.json();
// 处理返回的音频数据
const result = await processNonStreamAudio(data, {
audioField: 'data.audio',
dataType: 'base64',
mimeType: 'audio/mp3',
autoPlay: true,
onAudioData: (blob) => {
console.log('TTS音频生成成功,大小:', blob.size);
},
onError: (error) => {
console.error('TTS失败:', error);
alert('语音合成失败,请重试');
}
});
return result;
} catch (error) {
console.error('TTS请求失败:', error);
throw error;
}
}
// 使用
const button = document.querySelector('#speak-button');
button.addEventListener('click', async () => {
const text = document.querySelector('#text-input').value;
await textToSpeech(text);
});
```
### 场景2:音频文件上传预览
```typescript
import { processNonStreamAudio } from 'mstf-kit';
const fileInput = document.querySelector('#audio-upload');
const audioPreview = document.querySelector('#audio-preview');
fileInput.addEventListener('change', async (event) => {
const file = event.target.files[0];
if (!file) return;
// 验证文件类型
if (!file.type.startsWith('audio/')) {
alert('请选择音频文件');
return;
}
try {
// 处理音频文件
const result = await processNonStreamAudio(file, {
dataType: 'file',
onAudioData: (blob) => {
console.log('音频文件信息:', {
name: file.name,
size: blob.size,
type: blob.type
});
}
});
// 显示预览
audioPreview.src = result.url;
audioPreview.style.display = 'block';
} catch (error) {
console.error('处理音频文件失败:', error);
alert('无法加载音频文件');
}
});
```
### 场景3:多语言音频切换
```typescript
import { processBatchNonStreamAudio } from 'mstf-kit';
async function loadMultiLanguageAudio() {
// 获取多语言音频数据
const response = await fetch('/api/audio/multi-language');
const data = await response.json();
// 批量处理
const results = await processBatchNonStreamAudio(data.languages, {
audioField: 'audio',
dataType: 'base64',
mimeType: 'audio/mp3'
});
// 创建语言选择器
const languageSelector = document.querySelector('#language-selector');
const audioPlayer = document.querySelector('#audio-player');
results.forEach((result, index) => {
const language = data.languages[index];
// 添加选项
const option = document.createElement('option');
option.value = result.url;
option.textContent = language.name;
languageSelector.appendChild(option);
});
// 切换语言
languageSelector.addEventListener('change', (event) => {
audioPlayer.src = event.target.value;
audioPlayer.play();
});
}
loadMultiLanguageAudio();
```
### 场景4:音频消息系统
```typescript
import { processNonStreamAudio } from 'mstf-kit';
class AudioMessageSystem {
private audioCache = new Map<string, string>();
async loadAudioMessage(messageId: string) {
// 检查缓存
if (this.audioCache.has(messageId)) {
return this.audioCache.get(messageId);
}
// 获取音频消息
const response = await fetch(`/api/messages/${messageId}/audio`);
const data = await response.json();
// 处理音频
const result = await processNonStreamAudio(data, {
audioField: 'data.audio',
dataType: 'base64',
mimeType: 'audio/mp3',
onError: (error) => {
console.error(`加载音频消息 ${messageId} 失败:`, error);
}
});
// 缓存URL
this.audioCache.set(messageId, result.url);
return result.url;
}
async playAudioMessage(messageId: string) {
const url = await this.loadAudioMessage(messageId);
const audio = new Audio(url);
audio.play();
return audio;
}
clearCache() {
// 释放所有URL
this.audioCache.forEach(url => {
URL.revokeObjectURL(url);
});
this.audioCache.clear();
}
}
// 使用
const audioSystem = new AudioMessageSystem();
document.querySelectorAll('.audio-message').forEach(element => {
element.addEventListener('click', async () => {
const messageId = element.dataset.messageId;
await audioSystem.playAudioMessage(messageId);
});
});
```
## API 参考
### processNonStreamAudio
处理非流式音频响应的主函数。
```typescript
function processNonStreamAudio(
response: any,
options?: NonStreamAudioOptions
): Promise<NonStreamAudioResult>
```
**参数:**
- `response`: 响应数据,可以是完整的响应对象、纯数据对象或直接的音频数据
- `options`: 处理选项
**返回:**
Promise<NonStreamAudioResult>,包含:
- `blob`: 音频Blob对象
- `url`: 音频URL(可用于audio标签的src)
- `size`: 音频大小(字节)
- `mimeType`: 音频MIME类型
- `audio`: 音频元素(如果启用了自动播放)
### NonStreamAudioOptions
```typescript
interface NonStreamAudioOptions {
audioField?: string; // 音频数据字段路径
dataType?: AudioDataType; // 数据类型
mimeType?: string; // MIME类型
autoPlay?: boolean; // 是否自动播放
debug?: boolean; // 是否启用调试日志
onAudioData?: (blob: Blob) => void; // 音频数据回调
onError?: (error: Error) => void; // 错误回调
onComplete?: (blob?: Blob) => void; // 完成回调
}
```
### AudioDataType
```typescript
type AudioDataType = 'base64' | 'blob' | 'arraybuffer' | 'file';
```
## 注意事项
1. **内存管理**:使用 `URL.createObjectURL()` 创建的 URL 需要手动释放。如果不再使用音频,请调用 `URL.revokeObjectURL(url)` 释放内存。
2. **自动播放限制**:现代浏览器对自动播放有限制,可能需要用户交互才能播放音频。
3. **CORS 问题**:如果音频来自不同域,确保服务器设置了正确的 CORS 头。
4. **数据大小**:Base64 编码会增加约 33% 的数据大小,对于大文件建议使用 Blob 或 ArrayBuffer。
5. **浏览器兼容性**:确保目标浏览器支持 Web Audio API 和 Blob API。
## 错误处理
```typescript
try {
const result = await processNonStreamAudio(response, {
audioField: 'data.audio',
dataType: 'base64'
});
// 成功处理
console.log('音频URL:', result.url);
} catch (error) {
// 处理错误
if (error.message.includes('无法从路径')) {
console.error('字段路径错误,请检查 audioField 配置');
} else if (error.message.includes('无法检测音频数据类型')) {
console.error('数据类型检测失败,请手动指定 dataType');
} else {
console.error('未知错误:', error);
}
}
```
## 性能优化建议
1. **缓存音频 URL**:对于重复使用的音频,缓存 URL 避免重复处理
2. **批量处理**:使用 `processBatchNonStreamAudio` 批量处理多个音频
3. **懒加载**:只在需要时才加载和处理音频数据
4. **预加载**:对于即将使用的音频,可以提前加载
5. **释放资源**:及时释放不再使用的 URL 和 Blob
## 总结
`audioNonStream` 模块提供了一套完整、灵活、易用的非流式音频处理解决方案。无论是简单的 Base64 数据还是复杂的嵌套响应格式,都能轻松处理。配合完整的 TypeScript 类型支持和丰富的回调系统,可以满足各种音频处理需求。