data = f.read()
return Response(content=data, media_type="audio/mpeg")
- # 拉取有道 TTS(type=2 美式发音)
- url = "https://dict.youdao.com/dictvoice?audio=" + urllib.parse.quote(word) + "&type=2"
- req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
- try:
- with urllib.request.urlopen(req, timeout=10) as resp:
- data = resp.read()
- except urllib.error.URLError as e:
- raise HTTPException(status_code=502, detail=f"TTS upstream error: {e}")
+ # 多源 TTS:先有道(type=2 美式),失败回退百度翻译(本机可达,可覆盖有道无法合成的短语,无需 key)
+ sources = [
+ ("youdao", "https://dict.youdao.com/dictvoice?audio=" + urllib.parse.quote(word) + "&type=2",
+ {"User-Agent": "Mozilla/5.0"}),
+ ("baidu", "https://fanyi.baidu.com/gettts?lan=en&text=" + urllib.parse.quote(word) + "&spd=3",
+ {"User-Agent": "Mozilla/5.0", "Referer": "https://fanyi.baidu.com/"}),
+ ]
+ data = None
+ last_err = None
+ for name, url, headers in sources:
+ try:
+ req = urllib.request.Request(url, headers=headers)
+ with urllib.request.urlopen(req, timeout=10) as resp:
+ ct = resp.headers.get("Content-Type", "")
+ if ct.startswith("application/json"):
+ last_err = f"{name} returned json (no audio)"
+ continue
+ data = resp.read()
+ if data:
+ break
+ except urllib.error.URLError as e:
+ last_err = f"{name}: {e}"
+ continue
if not data:
- raise HTTPException(status_code=502, detail="TTS empty response")
+ raise HTTPException(status_code=502, detail=f"TTS upstream error: {last_err}")
# 写入缓存
try: