FunAudioLLM / CosyVoice

Multi-lingual large voice generation model, providing inference, training and deployment full-stack ability.
https://funaudiollm.github.io/
Apache License 2.0
6.31k stars 673 forks source link

调用 gradio api 报错:httpx.HTTPStatusError: Client error '403 Forbidden' #481

Open smallpize opened 1 month ago

smallpize commented 1 month ago

Describe the bug 更新版本后,调用 gradio api 报错:httpx.HTTPStatusError: Client error '403 Forbidden' 在 webUI 上,合成声音后,点击下载无反应

编写一个简短的脚本:

from gradio_client import Client, file

client = Client("http://localhost:7860/")
result = client.predict(
                tts_text="我是通义实验室语音团队全新推出的生成式语音大模型,提供舒适自然的语音合成能力。",
                prompt_wav_upload=None,  # 或使用本地文件路径
                prompt_wav_record=None,  # 或使用本地文件路径
                mode_checkbox_group="预训练音色",
                sft_dropdown="中文女",
                api_name="/generate_audio"
)
print(result)

执行报错:

Loaded as API: http://localhost:7860/ ✔
Traceback (most recent call last):
  File "test.py", line 4, in <module>
    result = client.predict(
  File "/anaconda/envs/cosyvoice/lib/python3.8/site-packages/gradio_client/client.py", line 469, in predict
    return self.submit(
  File "/anaconda/envs/cosyvoice/lib/python3.8/site-packages/gradio_client/client.py", line 1513, in result
    return super().result(timeout=timeout)
  File "/anaconda/envs/cosyvoice/lib/python3.8/concurrent/futures/_base.py", line 444, in result
    return self.__get_result()
  File "/anaconda/envs/cosyvoice/lib/python3.8/concurrent/futures/_base.py", line 389, in __get_result
    raise self._exception
  File "/anaconda/envs/cosyvoice/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/anaconda/envs/cosyvoice/lib/python3.8/site-packages/gradio_client/client.py", line 1124, in _inner
    predictions = self.process_predictions(*predictions)
  File "/anaconda/envs/cosyvoice/lib/python3.8/site-packages/gradio_client/client.py", line 1298, in process_predictions
    predictions = self.download_files(*predictions)
  File "/anaconda/envs/cosyvoice/lib/python3.8
/site-packages/gradio_client/client.py", line 1311, in download_files
    data_ = utils.traverse(data_, self._download_file, utils.is_file_obj)
  File "/anaconda/envs/cosyvoice/lib/python3.8/site-packages/gradio_client/utils.py", line 984, in traverse
    new_obj.append(traverse(item, func, is_root))
  File "/anaconda/envs/cosyvoice/lib/python3.8/site-packages/gradio_client/utils.py", line 975, in traverse
    return func(json_obj)
  File "/anaconda/envs/cosyvoice/lib/python3.8/site-packages/gradio_client/client.py", line 1397, in _download_file
    response.raise_for_status()
  File "/anaconda/envs/cosyvoice/lib/python3.8/site-packages/httpx/_models.py", line 763, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Client error '403 Forbidden' for url 'http://localhost:7860/file=072a68ec-e557-4a3f-8892-21744a40dfd6/139670860235056/21'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403
smallpize commented 1 month ago

找到问题了,修改webUI:

原代码:audio_output = gr.Audio(label="合成音频", autoplay=True, streaming=True)

修改为:audio_output = gr.Audio(label="合成音频", autoplay=True, streaming=False)

smallpize commented 1 month ago

gr.Audio 组件的 streaming=True 时,通常会导致无法下载音频文件。这是由于以下原因:

  1. 流式音频的工作原理: 当 streaming=True 时,音频数据是以小块(chunks)的形式逐步传输的,而不是作为一个完整的文件。这种方式允许音频在生成的同时就开始播放,提供了更快的响应体验。

  2. 缺少完整文件: 由于音频是流式传输的,在播放过程中并没有生成一个完整的音频文件。这就意味着没有一个单一的、完整的文件可供下载。

  3. Gradio 的限制: Gradio 的 Audio 组件在流式模式下主要是为了实时播放而设计的,而不是为了提供下载功能。

  4. 浏览器限制: 浏览器通常需要完整的音频文件才能提供下载功能。

解决方案:

  1. 禁用流式传输: 如果下载功能对您的应用很重要,可以将 streaming 设置为 False

    audio_output = gr.Audio(label="合成音频", autoplay=True, streaming=False)

    这样会生成一个完整的音频文件,可以下载,但可能会增加首次播放的延迟。

  2. 双重输出: 您可以考虑使用两个音频输出组件,一个用于流式播放,另一个用于下载:

    audio_stream = gr.Audio(label="合成音频(流式播放)", autoplay=True, streaming=True)
    audio_download = gr.Audio(label="下载音频", streaming=False)
  3. 自定义下载按钮: 您可以实现一个自定义的下载功能,在流式传输完成后生成一个可下载的文件。

  4. 使用其他组件: 考虑使用 gr.File 组件来提供下载功能,同时保留 gr.Audio 用于流式播放。

  5. 后端处理: 在后端完成音频生成后,将完整的音频文件保存下来,然后提供一个下载链接。

选择哪种方法取决于您的具体需求和应用场景。如果即时播放和下载都很重要,可能需要结合使用上述的一些方法。

设置了 audio_output = gr.Audio(label="合成音频", autoplay=True, streaming=False) 。但是通过gradio API 调用的时候语音分成了多个文件地址

这个问题实际上不是由 generate_audio 函数的实现有关:

  1. 生成器函数的影响: 您的 generate_audio 函数是一个生成器函数(使用 yield 语句)。这意味着它不是一次性返回完整的音频,而是分段返回音频数据。

  2. Gradio的处理方式: 当 Gradio 处理一个生成器函数的输出时,它会为每个 yield 的值创建一个单独的输出。在 API 调用中,这表现为多个文件地址。

  3. streaming=False 的影响: 即使设置了 streaming=False,Gradio 仍然会处理生成器函数的每个输出。这就是为什么会返回多个文件地址。

  4. API 调用的行为: 在 API 调用中,Gradio 会返回函数每次 yield 的结果,而不是等待所有数据生成后合并为一个文件。

解决方案:

  1. 修改生成函数: 如果您希望在 API 调用中只返回一个完整的音频文件,您需要修改 generate_audio 函数,使其一次性返回完整的音频数据,而不是使用 yield。例如:

    def generate_audio(...):
       # ... 前面的代码保持不变 ...
    
       full_audio = []
       if mode_checkbox_group == '预训练音色':
           for i in cosyvoice.inference_sft(...):
               full_audio.append(i['tts_speech'].numpy().flatten())
       # ... 其他模式同理 ...
    
       return (target_sr, np.concatenate(full_audio))
  2. 使用两个不同的函数: 一个用于 Web 界面的流式输出,另一个用于 API 调用的完整输出。

  3. 在 API 端合并音频: 如果您需要保持当前的生成器函数不变,可以考虑在 API 调用端合并接收到的多个音频片段。

  4. 使用自定义组件: 创建一个自定义的 Gradio 组件,专门处理您的音频生成方式。

  5. 后处理: 在生成完所有音频片段后,将它们合并成一个文件,然后返回这个合并后的文件。

选择哪种方法取决于您的具体需求和应用场景。如果您主要关注 API 调用的行为,修改 generate_audio 函数以一次性返回完整音频可能是最直接的解决方案。如果您需要同时支持流式 Web 界面和单一文件 API 输出,可能需要实现两个不同的处理路径。

github-actions[bot] commented 1 day ago

This issue is stale because it has been open for 30 days with no activity.