feat: 组件封装,音频保存
This commit is contained in:
@@ -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} 个音频包")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user