diff --git a/dsLightRag/Routes/__pycache__/ttsRoute.cpython-310.pyc b/dsLightRag/Routes/__pycache__/ttsRoute.cpython-310.pyc index 99085838..279cce17 100644 Binary files a/dsLightRag/Routes/__pycache__/ttsRoute.cpython-310.pyc and b/dsLightRag/Routes/__pycache__/ttsRoute.cpython-310.pyc differ diff --git a/dsLightRag/Routes/ttsRoute.py b/dsLightRag/Routes/ttsRoute.py index d5401a74..32208ebe 100644 --- a/dsLightRag/Routes/ttsRoute.py +++ b/dsLightRag/Routes/ttsRoute.py @@ -1,23 +1,23 @@ import logging -import uuid -from typing import Optional -from fastapi import APIRouter, HTTPException, Query # 添加Query导入 +from fastapi import APIRouter, HTTPException, BackgroundTasks, Query from pydantic import BaseModel - +from typing import Optional +import os +import uuid +import time +from Util.ObsUtil import ObsUploader +from Config.Config import OBS_BUCKET, OBS_SERVER +# 导入TTS生成类 from Util.GengerateAudio import ByteDanceTTS -# 创建声音生成路由 -router = APIRouter(prefix="/api/tts", tags=["声音生成"]) - # 配置日志 logger = logging.getLogger(__name__) - -# 初始化TTS实例 +router = APIRouter(prefix="/api/tts", tags=["文生音频"]) +# 初始化TTS实例(全局单例,避免重复创建) tts_instance = ByteDanceTTS() class TextToSpeechRequest(BaseModel): - """文本转语音请求参数""" text: str voice_type: Optional[str] = None speed_ratio: Optional[float] = 1.0 @@ -26,16 +26,6 @@ class TextToSpeechRequest(BaseModel): encoding: Optional[str] = "mp3" -class TextToSpeechResponse(BaseModel): - """文本转语音响应""" - success: bool - message: str - audio_url: Optional[str] = None - audio_size: Optional[float] = None - audio_format: Optional[str] = None - request_id: Optional[str] = None - - @router.get("/voice-categories") async def get_voice_categories(): try: @@ -52,6 +42,7 @@ async def get_voice_categories(): detail=f"获取音色分类失败: {str(e)}" ) + # 恢复原始的音色列表接口路由 @router.get("/voices") async def get_voices_by_category(category: str = Query(...)): # 现在Query已定义 @@ -62,7 +53,7 @@ async def get_voices_by_category(category: str = Query(...)): # 现在Query已 "success": False, "message": f"未找到分类 '{category}' 下的音色" } - + return { "success": True, "data": voices, @@ -93,61 +84,62 @@ async def get_all_voices(): logger.error(f"获取所有音色分类和列表错误: {e}") raise HTTPException( status_code=500, - detail=f"获取所有音色分类和列表失败: {str(e)}" - ) + detail=f"获取所有音色分类和列表失败: {str(e)}") -@router.post("/generate", response_model=TextToSpeechResponse) -async def generate_audio(request: TextToSpeechRequest): - """ - 文本转语音接口 - 根据输入文本和语音参数生成音频文件 - """ +@router.post("/generate") +async def generate_audio(request: TextToSpeechRequest, background_tasks: BackgroundTasks): try: - # 生成唯一文件名 - import os - from datetime import datetime - - # 确保输出目录存在 + # 1. 生成唯一文件名和路径 + timestamp = int(time.time()) + filename = f"tts_{uuid.uuid4().hex[:8]}_{timestamp}.mp3" output_dir = "static/audio" os.makedirs(output_dir, exist_ok=True) - - # 生成唯一文件名 - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - unique_id = str(uuid.uuid4())[:8] - filename = f"tts_{timestamp}_{unique_id}.{request.encoding}" output_path = os.path.join(output_dir, filename) - - # 调用TTS工具生成音频 + + # 2. 使用ByteDanceTTS生成音频文件 + # ------------------- TTS生成逻辑开始 ------------------- audio_data = tts_instance.generate_audio( text=request.text, + output_path=output_path, voice_type=request.voice_type, speed_ratio=request.speed_ratio, volume_ratio=request.volume_ratio, pitch_ratio=request.pitch_ratio, - encoding=request.encoding, - output_path=output_path + encoding=request.encoding ) - - if audio_data: - # 构建可访问的URL - audio_url = f"/{output_path}" - - return TextToSpeechResponse( - success=True, - message="音频生成成功", - audio_url=audio_url, - audio_format=request.encoding, - request_id=str(uuid.uuid4()) - ) - else: - return TextToSpeechResponse( - success=False, - message="音频生成失败" - ) + + if not audio_data: + raise HTTPException(status_code=500, detail="TTS音频生成失败") + # ------------------- TTS生成逻辑结束 ------------------- + + # 3. 上传到OBS + obs_uploader = ObsUploader() + obs_object_key = f"HuangHai/tts/{filename}" + upload_success, upload_result = obs_uploader.upload_file(obs_object_key, output_path) + + if not upload_success: + # 上传失败,清理文件并抛出异常 + background_tasks.add_task(os.remove, output_path) if os.path.exists(output_path) else None + raise HTTPException(status_code=500, detail=f"OBS上传失败: {upload_result.get('errorMessage', '未知错误')}") + + # 4. 构造OBS访问URL + obs_url = f"https://{OBS_BUCKET}.{OBS_SERVER}/{obs_object_key}" + + # 5. 安排后台任务删除本地文件 + background_tasks.add_task(os.remove, output_path) if os.path.exists(output_path) else None + + # 6. 返回OBS URL + return { + "status": "success", + "message": "音频生成并上传成功", + "audio_url": obs_url, # 确保此处没有添加任何引号或反引号 + "filename": filename, + "audio_size": len(audio_data) / 1024 # 音频大小(KB) + } + except Exception as e: - logger.error(f"文本转语音接口错误: {e}") - raise HTTPException( - status_code=500, - detail=f"音频生成失败: {str(e)}" - ) \ No newline at end of file + # 捕获所有异常并清理文件 + if 'output_path' in locals() and os.path.exists(output_path): + background_tasks.add_task(os.remove, output_path) + raise HTTPException(status_code=500, detail=f"处理失败: {str(e)}") diff --git a/dsLightRag/Start.py b/dsLightRag/Start.py index 340a9f2f..24e3c6b8 100644 --- a/dsLightRag/Start.py +++ b/dsLightRag/Start.py @@ -64,7 +64,7 @@ app.add_middleware( ) # 挂载静态文件目录 -app.mount("/static", StaticFiles(directory="Static"), name="static") +app.mount("/static", StaticFiles(directory="static"), name="static") # 加载路由 app.include_router(zuowen_router) # 作文批阅路由 diff --git a/dsLightRag/static/audio/tts_20250902_074150_a7eb0d9a.mp3 b/dsLightRag/static/audio/tts_20250902_074150_a7eb0d9a.mp3 new file mode 100644 index 00000000..f48c6b5f Binary files /dev/null and b/dsLightRag/static/audio/tts_20250902_074150_a7eb0d9a.mp3 differ diff --git a/dsLightRag/static/audio/tts_20250902_074443_0df4889a.mp3 b/dsLightRag/static/audio/tts_20250902_074443_0df4889a.mp3 new file mode 100644 index 00000000..63bf21c2 Binary files /dev/null and b/dsLightRag/static/audio/tts_20250902_074443_0df4889a.mp3 differ diff --git a/dsLightRag/static/audio/tts_20250902_074755_81ca2382.mp3 b/dsLightRag/static/audio/tts_20250902_074755_81ca2382.mp3 new file mode 100644 index 00000000..abd4d984 Binary files /dev/null and b/dsLightRag/static/audio/tts_20250902_074755_81ca2382.mp3 differ diff --git a/dsLightRag/static/audio/tts_20250902_075228_90ccd2a8.mp3 b/dsLightRag/static/audio/tts_20250902_075228_90ccd2a8.mp3 new file mode 100644 index 00000000..86edace8 Binary files /dev/null and b/dsLightRag/static/audio/tts_20250902_075228_90ccd2a8.mp3 differ diff --git a/dsLightRag/static/text-to-speech.html b/dsLightRag/static/text-to-speech.html index b003c697..58eb5d90 100644 --- a/dsLightRag/static/text-to-speech.html +++ b/dsLightRag/static/text-to-speech.html @@ -486,11 +486,14 @@ const data = await response.json(); console.log('音频生成结果:', data); - if (data.success) { + if (data.status==='success') { // 显示成功消息 showSuccess('语音生成成功'); // 设置音频播放器 + if(data.audio_url){ + console.log('音频文件地址:', data.audio_url) + } audioPlayer.src = data.audio_url; audioResult.style.display = 'block';