From 503ae8a3644dc6a6f0f9b9e08378af033c9f334f Mon Sep 17 00:00:00 2001 From: Lilixu007 <1273914445@qq.com> Date: Thu, 5 Mar 2026 13:34:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E5=AD=97=E8=AF=86=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ASR测试指南.md | 189 +++++++++++++++++++++++++ ASR问题修复总结.md | 252 +++++++++++++++++++++++++++++++++ lover/main_simple.py | 30 +++- lover/oss_utils.py | 8 +- test_dashscope_asr_complete.py | 238 +++++++++++++++++++++++++++++++ test_oss_url_fix.py | 80 +++++++++++ test_real_mp3.py | 144 +++++++++++++++++++ test_wav_asr.py | 144 +++++++++++++++++++ xuniYou/pages/chat/phone.vue | 9 +- xuniYou/utils/request.js | 2 +- 10 files changed, 1088 insertions(+), 8 deletions(-) create mode 100644 ASR测试指南.md create mode 100644 ASR问题修复总结.md create mode 100644 test_dashscope_asr_complete.py create mode 100644 test_oss_url_fix.py create mode 100644 test_real_mp3.py create mode 100644 test_wav_asr.py diff --git a/ASR测试指南.md b/ASR测试指南.md new file mode 100644 index 0000000..8eb00d8 --- /dev/null +++ b/ASR测试指南.md @@ -0,0 +1,189 @@ +# ASR 语音识别测试指南 + +## 🎯 当前状态 + +### ✅ 已完成的修复 + +1. **前端修复**: + - 修复了 `onStop` 回调中的文件处理逻辑 + - 添加了 `sendAudioToASR` 方法通过 HTTP POST 发送音频 + - 移除了冲突的 WebSocket 备用方案 + - 改用 WAV 格式录音(兼容性最好) + +2. **后端修复**: + - 添加了新的 `/voice/call/asr` 端点处理 JSON 格式音频 + - 修复了环境变量加载问题 + - 改进了错误处理 + - 后端运行在端口 30102 + +3. **配置更新**: + - 前端 `baseURLPy` 更新为 `http://192.168.1.141:30102` + - 录音格式改为 WAV(16kHz, 单声道) + +## 📱 测试步骤 + +### 1. 确保后端运行 + +```bash +cd lover +python main_simple.py +``` + +应该看到: +``` +INFO: Uvicorn running on http://0.0.0.0:30102 +``` + +### 2. 测试后端 ASR 端点 + +```bash +python test_asr_fix.py +``` + +应该看到: +``` +✅ ASR 请求成功 +🎉 ASR 修复测试成功! +``` + +### 3. 在前端测试录音 + +1. 打开 uni-app 应用 +2. 进入语音通话页面 +3. 按住"按住说话"按钮 +4. 说话 2-3 秒 +5. 松开按钮 + +### 4. 查看日志 + +**前端控制台应该显示**: +``` +📁 开始处理录音文件 +✅ 文件读取成功,开始发送到ASR +📤 发送ASR请求... +✅ ASR响应: ... +``` + +**后端日志应该显示**: +``` +INFO - 收到 JSON ASR 请求,格式: wav +INFO - 解码音频数据成功,大小: XXX 字节 +INFO - 上传 WAV 文件到 OSS... +INFO - 调用 DashScope ASR... +INFO - ASR 任务已创建: ... +INFO - ASR 识别成功 +``` + +## 🔍 常见问题排查 + +### 问题 1:音频格式解码失败 + +**症状**: +``` +音频格式解码失败,请检查录音设置 +``` + +**解决方案**: +- 确认前端使用 WAV 格式录音 +- 检查录音参数:16kHz, 单声道 +- 查看后端日志确认音频数据大小 + +### 问题 2:未识别到语音内容 + +**症状**: +``` +音频中未检测到有效语音 +``` + +**原因**: +- 录音时间太短(< 1秒) +- 环境噪音太大 +- 说话声音太小 + +**解决方案**: +- 录音时间保持在 2-5 秒 +- 在安静环境测试 +- 靠近麦克风说话 + +### 问题 3:WebSocket 连接问题 + +**症状**: +``` +Expected URL scheme 'http' or 'https' but was 'file' +``` + +**原因**: +- 旧的 WebSocket 流程仍在运行 +- 前端代码没有更新 + +**解决方案**: +- 确认前端已移除 WebSocket 备用方案 +- 重新编译前端应用 +- 清除应用缓存 + +### 问题 4:后端连接失败 + +**症状**: +``` +由于目标计算机积极拒绝,无法连接 +``` + +**解决方案**: +- 确认后端正在运行:`netstat -an | findstr :30102` +- 检查防火墙设置 +- 确认前端配置的端口正确(30102) + +## 📝 预期结果 + +### 成功的录音识别流程 + +1. **用户操作**: + - 按住说话按钮 + - 说话 2-3 秒:"你好,今天天气怎么样" + - 松开按钮 + +2. **前端处理**: + - 录音停止 + - 读取 WAV 文件 + - 转换为 base64 + - 发送到 `/voice/call/asr` + +3. **后端处理**: + - 接收 base64 音频数据 + - 解码为二进制 + - 上传到 OSS + - 调用 DashScope ASR + - 返回识别结果 + +4. **用户看到**: + - Toast 提示:"识别: 你好,今天天气怎么样" + +## 🚀 下一步优化 + +1. **添加语音对话功能**: + - 将识别结果发送给 LLM + - 生成回复 + - 使用 TTS 播放回复 + +2. **优化用户体验**: + - 添加录音动画 + - 显示识别进度 + - 支持重新录音 + +3. **错误处理**: + - 网络错误重试 + - 超时处理 + - 友好的错误提示 + +## 📞 技术支持 + +如果遇到问题,请提供: +1. 前端控制台完整日志 +2. 后端服务器日志 +3. 录音文件大小和时长 +4. 网络环境信息 + +--- + +**最后更新**: 2026-03-04 +**版本**: v1.0 diff --git a/ASR问题修复总结.md b/ASR问题修复总结.md new file mode 100644 index 0000000..397f05c --- /dev/null +++ b/ASR问题修复总结.md @@ -0,0 +1,252 @@ +# ASR 语音识别问题修复总结 + +## 🔍 问题诊断 + +### 错误信息 +``` +Expected URL scheme 'http' or 'https' but was 'file' +``` + +### 问题根源 + +经过详细分析,发现了两个主要问题: + +#### 1. 后端 OSS URL 生成问题(已修复) +**位置**: `lover/oss_utils.py` + +**问题**: 当配置了 `ALIYUN_OSS_CDN_DOMAIN` 时,如果 CDN 域名没有包含协议前缀(http:// 或 https://),生成的 URL 会缺少协议,导致 DashScope ASR 无法识别。 + +**修复**: +```python +# 修复前 +file_url = f"{settings.ALIYUN_OSS_CDN_DOMAIN.rstrip('/')}/{object_key}" + +# 修复后 +cdn_domain = settings.ALIYUN_OSS_CDN_DOMAIN.rstrip('/') +# 确保 CDN 域名包含协议 +if not cdn_domain.startswith('http://') and not cdn_domain.startswith('https://'): + cdn_domain = f"https://{cdn_domain}" +file_url = f"{cdn_domain}/{object_key}" +``` + +#### 2. 前端 baseURLPy 未定义问题(已修复) +**位置**: `xuniYou/pages/chat/phone.vue` + +**问题**: 在 `sendAudioToASR` 方法中使用了 `this.baseURLPy`,但该属性没有在 data 中定义,导致 URL 构建失败。 + +**修复**: +```javascript +// 在 data() 中添加 +data() { + return { + // ... 其他属性 + baseURLPy: baseURLPy // 添加 baseURLPy 到 data + } +} +``` + +## ✅ 修复验证 + +### 1. OSS URL 生成测试 +```bash +python test_oss_url_fix.py +``` + +**结果**: +``` +✅ OSS 连接成功 +✅ 文件上传成功 +📍 生成的 URL: https://hello12312312.oss-cn-hangzhou.aliyuncs.com/voice_call/xxx.mp3 +✅ URL 格式正确(包含协议) +✅ URL 包含 Bucket 名称 +✅ 测试文件已删除 +🎉 OSS URL 生成测试通过! +``` + +### 2. DashScope ASR 完整测试 +```bash +python test_dashscope_asr_complete.py +``` + +**结果**: +``` +✅ 上传成功 +✅ 任务创建成功 +❌ 识别失败: SUCCESS_WITH_NO_VALID_FRAGMENT +💡 原因: 测试音频是正弦波,不包含有效语音 +``` + +**说明**: 这是预期结果,因为测试音频不包含真实语音。使用真实录音应该可以正常识别。 + +## 📋 DashScope ASR 官方文档要求 + +根据测试和官方文档,ASR 服务要求: + +### 1. 文件 URL 要求 +- ✅ 必须使用 HTTPS 或 HTTP 协议 +- ✅ URL 必须可公开访问 +- ✅ 文件必须存储在 OSS 或其他云存储服务 + +### 2. 音频格式要求 +- ✅ 支持格式: WAV, MP3, PCM, OPUS, SPEEX, AMR +- ✅ 推荐采样率: 16kHz +- ✅ 推荐声道: 单声道 +- ✅ 推荐编码: 16-bit PCM + +### 3. 音频内容要求 +- ⚠️ 必须包含有效的语音内容 +- ⚠️ 音频时长建议 1-60 秒 +- ⚠️ 避免过多背景噪音 + +### 4. API 调用流程 +```python +# 1. 上传音频到 OSS +file_url = upload_audio_file(audio_data, "wav") + +# 2. 创建 ASR 任务 +task_response = Transcription.async_call( + model='paraformer-v2', + file_urls=[file_url], + parameters={ + 'format': 'wav', + 'sample_rate': 16000, + 'enable_words': False + } +) + +# 3. 等待识别完成 +result = Transcription.wait(task=task_id) + +# 4. 解析结果 +if result.output.task_status == "SUCCEEDED": + # 下载转录结果 + transcription_url = result.output.results[0]['transcription_url'] + response = requests.get(transcription_url) + transcription_data = response.json() + text = transcription_data['transcripts'][0]['text'] +``` + +## 🔧 常见错误码 + +### SUCCESS_WITH_NO_VALID_FRAGMENT +**含义**: 音频中未检测到有效语音片段 + +**可能原因**: +- 音频时长太短(< 0.5秒) +- 音频内容是纯音乐或噪音 +- 音频音量太小 +- 音频格式损坏 + +**解决方案**: +- 确保录音时长 > 1 秒 +- 在安静环境录音 +- 靠近麦克风说话 +- 检查录音设备 + +### FILE_DOWNLOAD_FAILED +**含义**: DashScope 无法下载音频文件 + +**可能原因**: +- OSS Bucket 权限设置不正确 +- 文件 URL 不可公开访问 +- 网络连接问题 + +**解决方案**: +- 检查 OSS Bucket 的公共读权限 +- 确保文件 URL 可以在浏览器中直接访问 +- 检查防火墙设置 + +### DECODE_ERROR +**含义**: 音频格式解码失败 + +**可能原因**: +- 音频格式不正确 +- 文件头信息损坏 +- 编码参数不匹配 + +**解决方案**: +- 使用标准的 WAV 或 MP3 格式 +- 确保采样率为 8kHz 或 16kHz +- 使用单声道录音 + +## 🚀 下一步测试 + +### 1. 前端测试 +1. 重新编译前端应用 +2. 打开语音通话页面 +3. 按住"按住说话"按钮 +4. 说话 2-3 秒:"你好,今天天气怎么样" +5. 松开按钮 +6. 查看识别结果 + +### 2. 预期结果 +**前端控制台**: +``` +📁 开始处理录音文件 +✅ 文件读取成功,开始发送到ASR +📤 发送ASR请求... +✅ ASR响应: {text: "你好,今天天气怎么样"} +``` + +**后端日志**: +``` +INFO - 收到 JSON ASR 请求,格式: wav +INFO - 解码音频数据成功,大小: XXX 字节 +INFO - 上传 WAV 文件到 OSS... +INFO - 文件上传成功: https://... +INFO - 调用 DashScope ASR... +INFO - ASR 任务已创建: xxx +INFO - ASR 识别成功 +INFO - 最终 ASR 识别结果: 你好,今天天气怎么样 +``` + +## 📝 配置检查清单 + +### 环境变量 (.env) +```bash +# DashScope API Key +DASHSCOPE_API_KEY=sk-xxx + +# OSS 配置 +ALIYUN_OSS_ACCESS_KEY_ID=xxx +ALIYUN_OSS_ACCESS_KEY_SECRET=xxx +ALIYUN_OSS_BUCKET_NAME=xxx +ALIYUN_OSS_ENDPOINT=https://oss-cn-hangzhou.aliyuncs.com +ALIYUN_OSS_CDN_DOMAIN=https://xxx.oss-cn-hangzhou.aliyuncs.com + +# ASR 配置 +VOICE_CALL_ASR_MODEL=paraformer-realtime-v2 +VOICE_CALL_ASR_SAMPLE_RATE=16000 +``` + +### OSS Bucket 权限 +- ✅ 公共读权限已开启 +- ✅ 跨域配置已设置(如需要) +- ✅ AccessKey 有上传和删除权限 + +### 网络配置 +- ✅ 后端服务运行在 0.0.0.0:30102 +- ✅ 防火墙允许 30102 端口 +- ✅ 前端配置正确的后端地址 + +## 🎯 总结 + +### 已修复的问题 +1. ✅ OSS URL 生成缺少协议前缀 +2. ✅ 前端 baseURLPy 未定义 +3. ✅ URL 格式验证逻辑 + +### 验证通过的功能 +1. ✅ OSS 连接和文件上传 +2. ✅ URL 格式正确性 +3. ✅ DashScope ASR API 调用流程 + +### 待真实录音测试 +1. ⏳ 前端录音功能 +2. ⏳ 完整的 ASR 识别流程 +3. ⏳ 识别结果展示 + +--- + +**最后更新**: 2026-03-05 +**修复版本**: v1.1 diff --git a/lover/main_simple.py b/lover/main_simple.py index 96fcbba..aab1808 100644 --- a/lover/main_simple.py +++ b/lover/main_simple.py @@ -10,7 +10,22 @@ import logging import dashscope from pathlib import Path +# 导入所有路由 +from lover.routers import config as config_router +from lover.routers import lover as lover_router +from lover.routers import user_basic as user_basic_router +from lover.routers import outfit as outfit_router +from lover.routers import chat as chat_router from lover.routers import voice_call as voice_call_router +from lover.routers import dance as dance_router +from lover.routers import dynamic as dynamic_router +from lover.routers import sing as sing_router +from lover.routers import friend as friend_router +from lover.routers import msg as msg_router +from lover.routers import huanxin as huanxin_router +from lover.routers import user as user_router +from lover.routers import music_library as music_library_router + from lover.response import ApiResponse from lover.config import settings @@ -41,8 +56,21 @@ app.add_middleware( allow_headers=["*"], ) -# 只包含语音通话路由 +# 包含所有路由 +app.include_router(config_router.router) +app.include_router(lover_router.router) +app.include_router(user_basic_router.router) +app.include_router(outfit_router.router) +app.include_router(chat_router.router) app.include_router(voice_call_router.router) +app.include_router(dance_router.router) +app.include_router(dynamic_router.router) +app.include_router(sing_router.router) +app.include_router(friend_router.router) +app.include_router(msg_router.router) +app.include_router(huanxin_router.router) +app.include_router(user_router.router) +app.include_router(music_library_router.router) @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): diff --git a/lover/oss_utils.py b/lover/oss_utils.py index 1968316..4cb72a9 100644 --- a/lover/oss_utils.py +++ b/lover/oss_utils.py @@ -93,7 +93,11 @@ def upload_audio_file(audio_data: bytes, file_extension: str = "wav") -> str: # 构建公网访问 URL if settings.ALIYUN_OSS_CDN_DOMAIN: # 使用 CDN 域名 - file_url = f"{settings.ALIYUN_OSS_CDN_DOMAIN.rstrip('/')}/{object_key}" + cdn_domain = settings.ALIYUN_OSS_CDN_DOMAIN.rstrip('/') + # 确保 CDN 域名包含协议 + if not cdn_domain.startswith('http://') and not cdn_domain.startswith('https://'): + cdn_domain = f"https://{cdn_domain}" + file_url = f"{cdn_domain}/{object_key}" else: # 使用默认域名 - 修复 URL 格式 endpoint_clean = settings.ALIYUN_OSS_ENDPOINT.replace('https://', '').replace('http://', '').rstrip('/') @@ -102,7 +106,7 @@ def upload_audio_file(audio_data: bytes, file_extension: str = "wav") -> str: logger.info(f"文件上传成功: {object_key} -> {file_url}") # 验证 URL 格式 - if not file_url.startswith('https://'): + if not file_url.startswith('http://') and not file_url.startswith('https://'): logger.error(f"URL 格式错误: {file_url}") raise Exception(f"生成的 URL 格式不正确: {file_url}") diff --git a/test_dashscope_asr_complete.py b/test_dashscope_asr_complete.py new file mode 100644 index 0000000..1e5f9d4 --- /dev/null +++ b/test_dashscope_asr_complete.py @@ -0,0 +1,238 @@ +""" +完整测试 DashScope ASR 批量识别 +按照官方文档要求测试 +""" +import os +import sys +import time +import logging + +# 添加 lover 目录到路径 +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'lover')) + +from lover.config import settings +from lover.oss_utils import upload_audio_file, delete_audio_file +import dashscope +from dashscope.audio.asr import Transcription + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +def create_test_audio(): + """创建一个简单的测试音频(PCM 格式)""" + # 生成 1 秒的 16kHz 单声道 PCM 数据 + # 简单的正弦波 + import struct + import math + + sample_rate = 16000 + duration = 2 # 2 秒 + frequency = 440 # A4 音符 + + samples = [] + for i in range(sample_rate * duration): + # 生成正弦波 + value = int(32767 * 0.3 * math.sin(2 * math.pi * frequency * i / sample_rate)) + samples.append(struct.pack('= max_wait: + print(f"\n⏰ 等待超时({max_wait}秒)") + return False + + except Exception as e: + print(f"❌ ASR 调用失败: {e}") + import traceback + traceback.print_exc() + return False + + finally: + # 清理 OSS 文件 + print(f"\n🗑️ 清理 OSS 文件...") + try: + delete_audio_file(file_url) + print(f"✅ 文件已删除") + except Exception as e: + print(f"⚠️ 删除失败: {e}") + + print(f"\n" + "=" * 60) + print("🎉 DashScope ASR 测试完成!") + print("=" * 60) + + print(f"\n📚 官方文档要求总结:") + print(f" 1. ✅ 文件必须通过 HTTPS URL 访问") + print(f" 2. ✅ 支持的格式: WAV, MP3, PCM 等") + print(f" 3. ✅ 推荐采样率: 16kHz") + print(f" 4. ✅ 推荐声道: 单声道") + print(f" 5. ⚠️ 音频必须包含有效语音内容") + + return True + +if __name__ == "__main__": + success = test_dashscope_asr() + sys.exit(0 if success else 1) diff --git a/test_oss_url_fix.py b/test_oss_url_fix.py new file mode 100644 index 0000000..4a1182b --- /dev/null +++ b/test_oss_url_fix.py @@ -0,0 +1,80 @@ +""" +测试 OSS URL 生成修复 +""" +import os +import sys + +# 添加 lover 目录到路径 +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'lover')) + +from lover.config import settings +from lover.oss_utils import test_oss_connection, upload_audio_file, delete_audio_file +import logging + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +def test_url_generation(): + """测试 URL 生成是否正确""" + print("=" * 60) + print("测试 OSS URL 生成") + print("=" * 60) + + # 显示配置 + print(f"\n📋 当前配置:") + print(f" Bucket: {settings.ALIYUN_OSS_BUCKET_NAME}") + print(f" Endpoint: {settings.ALIYUN_OSS_ENDPOINT}") + print(f" CDN Domain: {settings.ALIYUN_OSS_CDN_DOMAIN}") + print(f" AccessKeyId: {settings.ALIYUN_OSS_ACCESS_KEY_ID[:8]}***") + + # 测试连接 + print(f"\n🔌 测试 OSS 连接...") + if not test_oss_connection(): + print("❌ OSS 连接失败") + return False + + print("✅ OSS 连接成功") + + # 创建测试音频数据 + print(f"\n📤 测试文件上传...") + test_audio = b"test audio data" * 100 # 简单的测试数据 + + try: + file_url = upload_audio_file(test_audio, "mp3") + print(f"✅ 文件上传成功") + print(f"📍 生成的 URL: {file_url}") + + # 验证 URL 格式 + if file_url.startswith('https://') or file_url.startswith('http://'): + print("✅ URL 格式正确(包含协议)") + else: + print(f"❌ URL 格式错误: {file_url}") + return False + + # 验证 URL 结构 + if settings.ALIYUN_OSS_BUCKET_NAME in file_url: + print("✅ URL 包含 Bucket 名称") + else: + print(f"⚠️ URL 不包含 Bucket 名称") + + # 清理测试文件 + print(f"\n🗑️ 清理测试文件...") + if delete_audio_file(file_url): + print("✅ 测试文件已删除") + else: + print("⚠️ 测试文件删除失败(可能需要手动清理)") + + print(f"\n" + "=" * 60) + print("🎉 OSS URL 生成测试通过!") + print("=" * 60) + return True + + except Exception as e: + print(f"❌ 测试失败: {e}") + import traceback + traceback.print_exc() + return False + +if __name__ == "__main__": + success = test_url_generation() + sys.exit(0 if success else 1) diff --git a/test_real_mp3.py b/test_real_mp3.py new file mode 100644 index 0000000..461da1e --- /dev/null +++ b/test_real_mp3.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +""" +使用真实的 MP3 文件测试 ASR +""" +import sys +import os +sys.path.append('.') + +import requests +import base64 +import logging + +# 设置日志 +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +def create_real_mp3(): + """创建一个真实的 MP3 文件""" + try: + from pydub import AudioSegment + from pydub.generators import Sine + + # 生成 3 秒的正弦波音频 + duration_ms = 3000 + frequency = 440 # A4 音符 + + # 生成音频 + audio = Sine(frequency).to_audio_segment(duration=duration_ms) + + # 设置为 16kHz 单声道 + audio = audio.set_frame_rate(16000).set_channels(1) + + # 导出为 MP3 + mp3_file = "test_audio_real.mp3" + audio.export(mp3_file, format="mp3", bitrate="64k") + + logger.info(f"创建真实 MP3 文件: {mp3_file}") + return mp3_file + + except ImportError: + logger.error("需要安装 pydub: pip install pydub") + logger.info("使用备用方案:创建简单的 MP3 头") + + # 创建一个最小的 MP3 文件 + # 这是一个有效的 MP3 文件头 + mp3_data = bytearray([ + 0xFF, 0xFB, 0x90, 0x00, # MP3 同步字和头信息 + ]) + + # 添加一些音频数据 + mp3_data.extend(b'\x00' * 1000) + + mp3_file = "test_audio_simple.mp3" + with open(mp3_file, 'wb') as f: + f.write(mp3_data) + + logger.info(f"创建简单 MP3 文件: {mp3_file}") + return mp3_file + +def test_mp3_asr(): + """测试 MP3 ASR""" + + # 创建 MP3 文件 + mp3_file = create_real_mp3() + + try: + # 读取 MP3 文件 + with open(mp3_file, 'rb') as f: + mp3_data = f.read() + + logger.info(f"MP3 文件大小: {len(mp3_data)} 字节") + + # 转换为 base64 + mp3_base64 = base64.b64encode(mp3_data).decode('utf-8') + logger.info(f"Base64 编码长度: {len(mp3_base64)}") + + # 准备请求数据 + request_data = { + 'audio_data': mp3_base64, + 'format': 'mp3' + } + + # 发送请求到后端 + url = "http://192.168.1.141:30102/voice/call/asr" + headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer test_token' + } + + logger.info(f"发送 ASR 请求到: {url}") + + response = requests.post(url, json=request_data, headers=headers, timeout=60) + + logger.info(f"响应状态码: {response.status_code}") + logger.info(f"响应内容: {response.text}") + + if response.status_code == 200: + result = response.json() + logger.info(f"✅ ASR 请求成功") + logger.info(f"识别结果: {result}") + + if 'data' in result and 'text' in result['data']: + text = result['data']['text'] + logger.info(f"🎯 识别文本: {text}") + + # 检查结果 + if "未识别到语音内容" in text or "音频中未检测到有效语音" in text: + logger.info("✅ MP3 格式正确,但没有检测到语音(这是预期的,因为是纯音调)") + return True + elif "音频格式解码失败" in text or "DECODE_ERROR" in text: + logger.error("❌ MP3 格式有问题") + return False + else: + logger.info("✅ ASR 处理成功") + return True + else: + logger.warning("响应格式不符合预期") + return False + else: + logger.error(f"❌ ASR 请求失败: {response.status_code}") + return False + + except Exception as e: + logger.error(f"❌ 测试失败: {e}") + import traceback + logger.error(f"错误堆栈: {traceback.format_exc()}") + return False + finally: + # 清理文件 + try: + if os.path.exists(mp3_file): + os.remove(mp3_file) + except: + pass + +if __name__ == "__main__": + logger.info("开始测试真实 MP3 ASR...") + success = test_mp3_asr() + + if success: + logger.info("🎉 MP3 ASR 测试成功!") + else: + logger.error("💥 MP3 ASR 测试失败") + sys.exit(1) \ No newline at end of file diff --git a/test_wav_asr.py b/test_wav_asr.py new file mode 100644 index 0000000..c51b884 --- /dev/null +++ b/test_wav_asr.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +""" +测试 WAV 格式 ASR +""" +import sys +import os +sys.path.append('.') + +import requests +import base64 +import wave +import struct +import math +import logging + +# 设置日志 +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +def create_wav_file(): + """创建一个标准的 WAV 文件""" + sample_rate = 16000 + duration = 3 # 3 秒 + + # 生成音频样本 + samples = [] + for i in range(sample_rate * duration): + t = i / sample_rate + # 生成复合波形,模拟语音 + f0 = 200 + 100 * math.sin(2 * math.pi * 0.5 * t) # 变化的基频 + sample = 0 + for harmonic in range(1, 5): + amplitude = 1.0 / harmonic + sample += amplitude * math.sin(2 * math.pi * f0 * harmonic * t) + + # 添加包络 + envelope = 0.5 * (1 + math.sin(2 * math.pi * 2 * t)) + final_sample = sample * envelope * 0.3 + + # 转换为 16-bit 整数 + sample_int = int(16000 * final_sample) + sample_int = max(-32767, min(32767, sample_int)) + samples.append(sample_int) + + # 写入 WAV 文件 + wav_file = "test_audio.wav" + with wave.open(wav_file, 'wb') as wav: + wav.setnchannels(1) # 单声道 + wav.setsampwidth(2) # 16-bit + wav.setframerate(sample_rate) # 16kHz + + # 写入样本数据 + for sample in samples: + wav.writeframes(struct.pack('