#!/usr/bin/env python3 """ 流式 TTS 服务器 - 实时音频流 """ import asyncio import argparse import edge_tts from pathlib import Path from flask import Flask, Response, send_file import threading app = Flask(__name__) # 全局配置 VOICES = { 'zh': 'zh-CN-XiaoxiaoNeural', 'zh-hk': 'zh-HK-HiuMaanNeural', 'en': 'en-US-AriaNeural', 'en-gb': 'en-GB-SoniaNeural', 'jp': 'ja-JP-NanamiNeural', 'kr': 'ko-KR-SunHiNeural', } DEFAULT_TEXT = """ Welcome to TTS Streamer. This is a test message. 欢迎使用文本转音频流服务。这是测试消息。 """ def detect_language(text: str) -> str: """检测语言""" if any('\u3040' <= c <= '\u309f' or '\u30a0' <= c <= '\u30ff' for c in text[:100]): return 'jp' if any('\uac00' <= c <= '\ud7af' for c in text[:100]): return 'kr' if any('\u4e00' <= c <= '\u9fff' for c in text[:100]): return 'zh' return 'en' async def generate_audio_stream(text: str, voice_code: str = 'auto'): """生成音频流""" if voice_code == 'auto': voice_code = detect_language(text) voice = VOICES.get(voice_code, VOICES['zh']) communicate = edge_tts.Communicate(text, voice) async for chunk in communicate.stream(): if chunk["type"] == "audio": yield chunk["data"] def run_async_stream(text: str, voice_code: str): """在同步上下文中运行异步流""" loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) async def stream_generator(): async for chunk in generate_audio_stream(text, voice_code): yield chunk # 转换为同步生成器 gen = stream_generator() while True: try: chunk = loop.run_until_complete(gen.__anext__()) yield chunk except StopAsyncIteration: break @app.route('/stream') def stream_audio(): """音频流端点""" text = app.config.get('TEXT', DEFAULT_TEXT) voice = app.config.get('VOICE', 'auto') return Response( run_async_stream(text, voice), mimetype='audio/mpeg', headers={ 'Content-Type': 'audio/mpeg', 'Accept-Ranges': 'bytes', 'Cache-Control': 'no-cache' } ) @app.route('/') def index(): """首页""" text = app.config.get('TEXT', DEFAULT_TEXT)[:200] return f"""

🔊 TTS Streamer

当前文本: {text}...

点击播放: /stream


或使用播放器直接打开: http://服务器IP:端口/stream

""" def serve_file(input_file: str, port: int = 8080, voice: str = 'auto'): """提供文件流服务""" # 读取文件 path = Path(input_file) if not path.exists(): print(f"❌ 文件不存在: {input_file}") return with open(input_file, 'r', encoding='utf-8') as f: text = f.read() # 配置 app.config['TEXT'] = text app.config['VOICE'] = voice print(f"🎙️ 准备播放: {input_file}") print(f"🌐 访问地址:") print(f" http://0.0.0.0:{port}/stream") print(f" http://0.0.0.0:{port}/ (网页)") print(f"\n📝 语言: {detect_language(text)}") print("按 Ctrl+C 停止服务") # 启动服务 app.run(host='0.0.0.0', port=port, threaded=True) def main(): parser = argparse.ArgumentParser(description='TTS 流服务器') parser.add_argument('input', help='输入文本文件') parser.add_argument('--port', '-p', type=int, default=8080, help='端口 (默认: 8080)') parser.add_argument('--voice', '-v', default='auto', help='语音代码') args = parser.parse_args() serve_file(args.input, args.port, args.voice) if __name__ == '__main__': main()