Flask API流式传输Elevenlabs音频在Safari中无法运行的问题
解决方案:修复Flask流式音频在Safari中的兼容性问题
以下是针对你的问题的具体修复步骤,解决Safari桌面端和iOS端无法加载流式音频的问题:
一、先修复原生MP3流式的响应头问题
Chrome对流式MP3的兼容性较好,但Safari对分块传输的音频有更严格的要求,补充必要的响应头可解决部分兼容问题:
from flask import stream_with_context, Response, request import requests @application.route('/get-audio', methods=['GET']) def get_audio(): data = request.args.get('data') def generate(): url = "https://api.elevenlabs.io/v1/text-to-speech/EXAVITQu4vr4xnSDxMaL/stream" headers = { "Accept": "audio/mpeg", "Content-Type": "application/json", "xi-api-key": "api_key" } payload = { "text": data, "model_id": "eleven_monolingual_v1", "voice_settings": { "stability": 0.5, "similarity_boost": 0.5 } } try: response = requests.post(url, json=payload, headers=headers, stream=True) response.raise_for_status() for chunk in response.iter_content(chunk_size=8192): if chunk: # 跳过空块避免无效数据 yield chunk except requests.RequestException as e: print(f"Error fetching audio: {e}") yield b'' # 添加Safari需要的响应头 response_headers = { 'Cache-Control': 'no-cache', 'Transfer-Encoding': 'chunked', 'Accept-Ranges': 'bytes' } return Response(stream_with_context(generate()), content_type='audio/mpeg', headers=response_headers)
二、正确实现流式转AAC(彻底解决Safari兼容性)
你之前的FFmpeg用法错误,communicate()会等待进程结束才返回输出,无法实现流式处理。以下是正确的实时转换方式:
from flask import stream_with_context, Response, request import requests import subprocess @application.route('/get-audio', methods=['GET']) def get_audio(): data = request.args.get('data') return Response(stream_with_context(generate_track(data)), content_type="audio/aac", headers={ 'Cache-Control': 'no-cache', 'Transfer-Encoding': 'chunked' }) def generate_track(data): url = "https://api.elevenlabs.io/v1/text-to-speech/EXAVITQu4vr4xnSDxMaL/stream" headers = { "Accept": "audio/mpeg", "Content-Type": "application/json", "xi-api-key": "api_key" } payload = { "text": data, "model_id": "eleven_monolingual_v1", "voice_settings": { "stability": 0.5, "similarity_boost": 0.5 } } try: response = requests.post(url, json=payload, headers=headers, stream=True) response.raise_for_status() # 配置FFmpeg参数:输出Safari支持的流式ADTS格式AAC ffmpeg_cmd = [ "ffmpeg", "-i", "pipe:0", # 从标准输入读取MP3 "-vn", # 禁用视频流 "-c:a", "aac", # 编码为AAC "-b:a", "128k", # 设置比特率 "-f", "adts", # 输出ADTS格式(适合流式传输) "-movflags", "frag_keyframe+empty_moov", # 优化流式容器 "-" # 输出到标准输出 ] # 启动FFmpeg进程 ffmpeg_process = subprocess.Popen( ffmpeg_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True ) try: # 流式写入MP3数据到FFmpeg,并实时读取转换后的AAC for audio_chunk in response.iter_content(chunk_size=4096): if audio_chunk: ffmpeg_process.stdin.write(audio_chunk) ffmpeg_process.stdin.flush() # 循环读取输出直到暂时无数据 while True: aac_chunk = ffmpeg_process.stdout.read(4096) if not aac_chunk: break yield aac_chunk # 关闭输入,触发FFmpeg处理剩余数据 ffmpeg_process.stdin.close() # 读取最后剩余的AAC数据 remaining = ffmpeg_process.stdout.read() if remaining: yield remaining finally: # 清理进程,避免僵尸进程 ffmpeg_process.wait() # 打印FFmpeg错误日志用于调试 stderr = ffmpeg_process.stderr.read().decode() if stderr: print(f"FFmpeg stderr: {stderr}") except requests.RequestException as e: print(f"Error fetching audios: {e}") yield b''
三、关键修复点说明
- 响应头优化:
Cache-Control: no-cache避免Safari缓存不完整的音频流,Transfer-Encoding: chunked明确告知浏览器使用分块传输模式。 - FFmpeg流式处理:替换
communicate()为逐块写入stdin和读取stdout,确保音频流实时转换并输出,而非等待全部数据处理完成。 - 格式适配:使用
-f adts输出Safari原生支持的流式AAC格式,添加-movflags参数优化容器结构,适配流式传输场景。 - 错误防护:添加
response.raise_for_status()检查ElevenLabs API响应状态,避免传输错误的音频数据。
内容的提问来源于stack exchange,提问作者arn49
相关产品推荐
相关产品推荐

