[Bug] Windows 下使用 torchaudio>=2.9.0 进行 TTS 音频转换时报错 PermissionError [WinError 32]
### System Info / 系統信息
Describe the bug (描述 Bug)
在 Windows 系统上,当 torchaudio 版本 >= 2.9.0 时,Xinference 的 TTS 功能在将生成的音频张量保存为字节流时会抛出 PermissionError: [WinError 32]。这是因为底层代码使用了 tempfile.NamedTemporaryFile 并且在文件句柄未完全释放时尝试读取或删除它,触发了 Windows 的文件锁定机制。
To Reproduce (复现步骤)
在 Windows 系统上安装 Xinference(确保 torchaudio 版本 >= 2.9.0)。
启动 Xinference 并加载一个 TTS 模型(例如 ChatTTS)。
调用 /v1/audio/speech API 请求语音合成。
观察后台日志,会出现 [WinError 32] 另一个程序正在使用此文件 的报错,导致无法正常返回音频。
Expected behavior (预期行为)
TTS 请求应该顺利完成,将音频文件转换为字节流并返回给客户端,不抛出任何文件权限/锁定异常。
Environment (环境信息)
OS: Windows 11 (也存在于 Win10)
Python version: 3.12
Xinference version: (填上你当前使用的版本号,比如 v0.15.0 或你安装的版本)
torchaudio version: 2.9.0+ (任何大于等于 2.9.0 的版本)
Error logs (错误日志)
Traceback (most recent call last ):
File ".../xinference/deploy/utils.py", line XXX, in audio_to_bytes
with tempfile.NamedTemporaryFile(suffix="." + response_format) as f:
torchaudio.save(f.name, tensor, sample_rate, format=response_format)
# 接下来尝试读取或删除时会失败
...
PermissionError: [WinError 32] 另一个程序正在使用此文件,进程无法访问。
Root Cause Analysis & Suggested Fix (根因分析与修复建议)
根因分析:
在 xinference/deploy/utils.py 的 audio_to_bytes 函数中,针对 torchaudio >= 2.9.0 的分支使用了 tempfile.NamedTemporaryFile。在 Windows 上,torchaudio.save 底层 C++ 库可能会保持对文件的句柄占用,导致随后 Python 尝试读取文件内容或当离开 with 作用域自动删除文件时触发 WinError 32。
修复建议:
建议避免使用 NamedTemporaryFile 默认的自动删除机制,或者使用时间戳/随机字符串生成临时文件名,并在 try...finally 块中显式释放和清理。
以下是我本地测试通过的修改方案(使用时间戳命名并显式读取,避免锁冲突):
# 替换原有的 torchaudio >= 2.9.0 分支代码
import os
import time
import tempfile
temp_dir = tempfile.gettempdir()
temp_file_name = os.path.join(
temp_dir, f"xinference_tts_{int(time.time() * 1000)}.{response_format}"
)
try:
if response_pcm:
torchaudio.save(
temp_file_name,
tensor,
sample_rate,
format="wav",
encoding="PCM_S",
)
with open(temp_file_name, "rb") as f:
wav_bytes = f.read()
return _extract_pcm_from_wav_bytes(wav_bytes)
else:
torchaudio.save(
temp_file_name, tensor, sample_rate, format=response_format
)
with open(temp_file_name, "rb") as f:
return f.read()
except Exception as e:
logger.error(f"Failed to save audio to {temp_file_name}: {e}")
raise
finally:
# 可以在这里选择性地清理文件
# if os.path.exists(temp_file_name):
# os.remove(temp_file_name)
pass
### Running Xinference with Docker? / 是否使用 Docker 运行 Xinfernece?
- [ ] docker / docker
- [x] pip install / 通过 pip install 安装
- [ ] installation from source / 从源码安装
### Version info / 版本信息
v:3.0.0
### The command used to start Xinference / 用以启动 xinference 的命令
@echo off
chcp 65001 >nul
title Xinference 本地服务端
color 0A
set TMPDIR=D:\AI_Tools\Xinference\tmp
set TEMP=D:\AI_Tools\Xinference\tmp
set TMP=D:\AI_Tools\Xinference\tmp
:: 1. 进入工作目录
cd /d D:\AI_Tools\Xinference
:: 2. 激活虚拟环境
call xinference_env\Scripts\activate.bat
:: 3. 设置 HuggingFace 国内镜像 (加速模型下载)
set HF_ENDPOINT=https://hf-mirror.com
:: 4. 打印提示信息
echo ==========================================================
echo Xinference 正在启动中... 请勿关闭此窗口!
echo 启动成功后,请打开浏览器访问: http://127.0.0.1:9997
echo 如需停止服务,请按键盘上的 Ctrl + C
echo ==========================================================
echo.
:: 5. 启动 Xinference
xinference-local -H 127.0.0.1 -p 9997
:: 6. 异常退出保护
echo.
echo *** 服务已停止,请检查上方报错信息。 ***
pause
### Reproduction / 复现过程
在 Windows 系统上安装 Xinference(确保 torchaudio 版本 >= 2.9.0)。
启动 Xinference 并加载一个 TTS 模型(例如 ChatTTS)。
调用 /v1/audio/speech API 请求语音合成。
观察后台日志,会出现 [WinError 32] 另一个程序正在使用此文件 的报错,导致无法正常返回音频。
### Expected behavior / 期待表现
TTS 请求应该顺利完成,将音频文件转换为字节流并返回给客户端,不抛出任何文件权限/锁定异常。
0 条评论