diff --git a/.gitignore b/.gitignore
index 669d75e..cd887af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,3 +114,5 @@ node_modules/
*.njsproj
*.sln
*.sw?
+
+*.mp3
\ No newline at end of file
diff --git a/backend/app/api/v1/endpoints/tts.py b/backend/app/api/v1/endpoints/tts.py
index 6caafeb..106a283 100644
--- a/backend/app/api/v1/endpoints/tts.py
+++ b/backend/app/api/v1/endpoints/tts.py
@@ -1,10 +1,12 @@
-# tts.py
import uuid
import websockets
import time
import fastrand
import json
import asyncio
+import os
+import aiofiles
+from datetime import datetime
from typing import Dict, Any, Optional as OptionalType
from app.constants.tts import APP_ID, TOKEN, SPEAKER
@@ -34,8 +36,26 @@ EVENT_TaskRequest = 200
EVENT_TTSSentenceEnd = 351
EVENT_TTSResponse = 352
+# 音频文件保存目录
+TEMP_AUDIO_DIR = "./temp_audio"
+
+
+# 确保音频目录存在
+async def ensure_audio_dir():
+ """异步创建音频目录"""
+ if not os.path.exists(TEMP_AUDIO_DIR):
+ os.makedirs(TEMP_AUDIO_DIR, exist_ok=True)
+
+
+# 生成时间戳文件名
+def generate_audio_filename() -> str:
+ """生成基于时间戳的音频文件名"""
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3] # 精确到毫秒
+ return f"{timestamp}.mp3"
+
+
+# ... 保留所有原有的类定义和工具函数 ...
-# 所有类定义
class Header:
def __init__(self,
protocol_version=PROTOCOL_VERSION,
@@ -199,6 +219,8 @@ class TTSState:
self.session_id: OptionalType[str] = None
self.task: OptionalType[asyncio.Task] = None # 用于追踪异步任务
self.is_processing = False
+ self.audio_data = bytearray() # 用于收集音频数据
+ self.audio_filename = None # 保存的文件名
# 全局状态管理
@@ -305,6 +327,18 @@ async def create_tts_connection() -> websockets.WebSocketServerProtocol:
return volc_ws
+# 异步保存音频文件
+async def save_audio_file(audio_data: bytes, filename: str) -> str:
+ """异步保存音频文件"""
+ await ensure_audio_dir()
+ file_path = os.path.join(TEMP_AUDIO_DIR, filename)
+
+ async with aiofiles.open(file_path, 'wb') as f:
+ await f.write(audio_data)
+
+ return file_path
+
+
# 处理单个TTS任务
async def process_tts_task(websocket, message_id: str, text: str):
"""处理单个TTS任务(独立协程)"""
@@ -318,6 +352,8 @@ async def process_tts_task(websocket, message_id: str, text: str):
raise Exception(f"找不到TTS状态: {message_id}")
tts_state.is_processing = True
+ # 生成音频文件名
+ tts_state.audio_filename = generate_audio_filename()
# 创建独立的TTS连接
tts_state.volc_ws = await create_tts_connection()
@@ -373,8 +409,12 @@ async def process_tts_task(websocket, message_id: str, text: str):
elif res.optional.event == EVENT_TTSResponse:
audio_count += 1
- print(f"发送音频数据 [{message_id}] #{audio_count},大小: {len(res.payload)}")
- # 发送音频数据
+ print(f"收到音频数据 [{message_id}] #{audio_count},大小: {len(res.payload)}")
+
+ # 收集音频数据
+ tts_state.audio_data.extend(res.payload)
+
+ # 发送音频数据到前端
await websocket.send_json({
"id": audio_count,
"type": "tts_audio_data",
@@ -387,10 +427,20 @@ async def process_tts_task(websocket, message_id: str, text: str):
except asyncio.TimeoutError:
print(f"TTS响应超时 [{message_id}],强制结束")
- # 发送完成消息
+ # 异步保存音频文件
+ if tts_state.audio_data:
+ file_path = await save_audio_file(
+ bytes(tts_state.audio_data),
+ tts_state.audio_filename
+ )
+ print(f"音频文件已保存 [{message_id}]: {file_path}")
+
+ # 发送完成消息,包含文件路径
await websocket.send_json({
"type": "tts_audio_complete",
- "messageId": message_id
+ "messageId": message_id,
+ "audioFile": tts_state.audio_filename,
+ "audioPath": os.path.join(TEMP_AUDIO_DIR, tts_state.audio_filename) if tts_state.audio_data else None
})
print(f"TTS处理完成 [{message_id}],共发送 {audio_count} 个音频包")
diff --git a/web/components.d.ts b/web/components.d.ts
index 3400cc8..dea5305 100644
--- a/web/components.d.ts
+++ b/web/components.d.ts
@@ -9,6 +9,8 @@ declare module 'vue' {
export interface GlobalComponents {
Avatar: typeof import('./src/components/avatar.vue')['default']
Markdown: typeof import('./src/components/markdown.vue')['default']
+ Message_tools: typeof import('./src/components/MessageTools.vue')['default']
+ MessageTools: typeof import('./src/components/MessageTools.vue')['default']
NButton: typeof import('naive-ui')['NButton']
NCollapse: typeof import('naive-ui')['NCollapse']
NCollapseItem: typeof import('naive-ui')['NCollapseItem']
diff --git a/web/src/components/MessageTools.vue b/web/src/components/MessageTools.vue
new file mode 100644
index 0000000..e8aaa1f
--- /dev/null
+++ b/web/src/components/MessageTools.vue
@@ -0,0 +1,26 @@
+
+
+
+