From d0fc1f8cff51d01186f7b9b3ad781804ad5a1717 Mon Sep 17 00:00:00 2001 From: hubian <908234780@qq.com> Date: Wed, 22 Apr 2026 21:57:32 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DChatTTS=E9=9F=B3?= =?UTF-8?q?=E9=A2=91=E4=BB=A3=E7=90=86=E8=B7=AF=E7=94=B1=E5=92=8C=E9=9F=B3?= =?UTF-8?q?=E9=A2=91=E6=92=AD=E6=94=BE=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- logs/server.log | Bin 11206 -> 211236 bytes main.py | 29 ++++++++++++++++++++++++++++- static/tts.html | 37 +++++++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/logs/server.log b/logs/server.log index 43a164a8293ba63ac9bd5ddc4d7642d01b02756a..df137f3c91d00b228f7c69c443abe4076a5c4be5 100644 GIT binary patch delta 605 zcmcJMze~eF6vr{a3gRj*f}w&HB~9*fm)xZyB8@tT77RE!q{&6IBw(%;{VOc_2OQiS zyEr(zs)M_`Q~e8kNkxi?o6CE5_df5(_ub?1?Z@18z2+cH86T|PtAsnni_)6n#j~)ThomY7S4#qF{|=kUna3@LLXzf9$s$dfApxhtC` zLrhXKyB;9nSs+U+=tW6pNRi9tMbOvwe7|F$CaP;Ce2__PC+nqAF;eD15|qFosijbB z!l{&?Qu87R1>)x%LdqmP9gG?}2*6 DN+h`F delta 154 zcmZ4TiRW1O1f}URmdqT}6D^plD%;WwE^cCAfP-xc6gQVL zHa0RgQP5RTa(4|;&@U+|)-Nc^FUw3xEt>dIm(gHyBa1bY37BFunViq8yxE3*kNR{^ O3+AhA21cevv0MPJjx1sT diff --git a/main.py b/main.py index bc901cf..d538e01 100644 --- a/main.py +++ b/main.py @@ -4,9 +4,10 @@ import os import uvicorn +import aiohttp from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import FileResponse +from fastapi.responses import FileResponse, Response from fastapi.staticfiles import StaticFiles # 导入后端服务 @@ -24,6 +25,32 @@ app.add_middleware( allow_headers=["*"], ) + +# ChatTTS 音频代理(解决 HTTPS 页面访问 HTTP 资源问题) +@app.get("/chattts/audio/{filename}") +async def proxy_chattts_audio(filename: str): + """代理 ChatTTS 音频文件""" + chattts_url = os.getenv("CHATTTS_URL", "http://192.168.2.5:12002") + + try: + async with aiohttp.ClientSession() as session: + async with session.get( + f"{chattts_url}/audio/{filename}", + timeout=aiohttp.ClientTimeout(total=30) + ) as resp: + if resp.status != 200: + return Response(content=b'{"detail":"Audio not found"}', status_code=404, media_type="application/json") + + audio_data = await resp.read() + return Response( + content=audio_data, + media_type="audio/wav", + headers={"Cache-Control": "public, max-age=3600"} + ) + except Exception as e: + return Response(content=f'{"detail":"{str(e)}"}'.encode(), status_code=500, media_type="application/json") + + # 挂载 API app.mount("/api", api_app) diff --git a/static/tts.html b/static/tts.html index ae2d54e..f79d6d0 100644 --- a/static/tts.html +++ b/static/tts.html @@ -545,6 +545,25 @@ let currentVoice = 'zh-CN-XiaoxiaoNeural'; let autoPlay = true; // 自动播放开关 let volumeLevel = 1.5; // 音量倍率 + let audioUnlocked = false; // 音频播放是否解锁 + + // 解锁音频播放(浏览器需要用户交互后才能自动播放) + function unlockAudio() { + if (!audioUnlocked) { + // 创建一个静音音频来解锁 + const silentAudio = new Audio(); + silentAudio.play().then(() => { + audioUnlocked = true; + console.log('音频播放已解锁'); + }).catch(e => { + console.log('音频解锁失败:', e); + }); + } + } + + // 页面点击解锁音频 + document.addEventListener('click', unlockAudio, { once: true }); + document.addEventListener('touchstart', unlockAudio, { once: true }); // 元素 const statusDot = document.getElementById('statusDot'); @@ -937,11 +956,25 @@ }; audio.onended = () => { - icon.textContent = url.startsWith('/audio') || url.startsWith('http') ? '🔊' : '▶️'; + icon.textContent = url.startsWith('/audio') || url.startsWith('http') || url.startsWith('blob:') ? '🔊' : '▶️'; btn.classList.remove('playing'); }; - audio.play(); + audio.onerror = (e) => { + console.error('音频播放失败:', url, e); + icon.textContent = '❌'; + btn.classList.remove('playing'); + }; + + // 添加播放失败的catch + audio.play().catch(e => { + console.error('播放被阻止:', e); + icon.textContent = '🔇'; + // 提示用户点击播放 + if (e.name === 'NotAllowedError') { + showError('请先点击页面解锁音频播放'); + } + }); } // 显示加载