You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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''

三、关键修复点说明

  1. 响应头优化:Cache-Control: no-cache避免Safari缓存不完整的音频流,Transfer-Encoding: chunked明确告知浏览器使用分块传输模式。
  2. FFmpeg流式处理:替换communicate()为逐块写入stdin和读取stdout,确保音频流实时转换并输出,而非等待全部数据处理完成。
  3. 格式适配:使用-f adts输出Safari原生支持的流式AAC格式,添加-movflags参数优化容器结构,适配流式传输场景。
  4. 错误防护:添加response.raise_for_status()检查ElevenLabs API响应状态,避免传输错误的音频数据。

内容的提问来源于stack exchange,提问作者arn49

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:10:04