F5-TTS文本语音合成模型的使用和接口封装,tts合成音频,http流式输出,音频采样率转换
F5-TTS文本语音生成模型
1. F5-TTS的简介
2024年10月8日,上海交通大学团队发布,F5-TTS (A Fairytaler that Fakes Fluent and Faithful Speech with Flow Matching) 是一款基于扩散Transformer和ConvNeXt V2的文本转语音 (TTS) 模型。F5-TTS旨在生成流畅且忠实的语音,其训练速度和推理速度都得到了提升。 项目还提供了一个名为E2 TTS的模型,它是论文中模型的更接近的复现版本,基于Flat-UNet Transformer。 预训练模型已发布在Hugging Face和Model Scope上。
总而言之,F5-TTS是一个功能强大且易于使用的TTS模型,它结合了扩散模型和流匹配技术,实现了快速训练、快速推理和高质量的语音生成。 其提供的Gradio应用和CLI工具也方便了用户的使用。 项目文档较为完善,方便用户快速上手。
GitHub地址:https://github.com/SWivid/F5-TTS
论文地址:https://arxiv.org/abs/2410.06885
2.模型特点:
快速训练和推理: 相比于其他模型,F5-TTS的训练和推理速度更快。
流畅逼真的语音: 采用流匹配技术,生成更流畅、更自然、更忠实的语音。
基于扩散Transformer和ConvNeXt V2: 利用先进的架构,提升模型性能。
多风格/多说话人生成: 支持多风格和多说话人的语音生成。
提供Gradio应用: 提供友好的图形用户界面,方便用户进行推理和微调。
支持语音聊天: 通过集成Qwen2.5-3B-Instruct模型,支持语音聊天功能。
提供了E2 TTS模型: 作为论文中模型的更接近的复现版本,方便研究者复现论文结果。
Sway Sampling: 一种推理时间的流步骤采样策略,极大地提高了性能。
3.F5-TTS的安装和使用方法
环境配置
- 使用conda创建虚拟环境
创建一个Python 3.10的conda环境 (也可以使用virtualenv):conda create -n f5-tts python=3.10conda activate f5-tts
- 安装PyTorch和Torchaudio依赖
安装PyTorch和Torchaudio,CUDA版本根据你的显卡选择:pip install torch==2.3.0+cu118 torchaudio==2.3.0+cu118 --extra-index-url https://download.pytorch.org/whl/cu118
克隆项目,安装环境依赖
git clone https://github.com/SWivid/F5-TTS.gitcd F5-TTSpip install -e .
4.推理
- 提供了三种推理方式:
1、Gradio应用 (Web界面)
运行 f5-tts_infer-gradio 命令启动Gradio应用,支持基本TTS、多风格/多说话人生成和基于Qwen2.5-3B-Instruct的语音聊天。可以使用 --port 和 --host 参数指定端口和主机,使用 --share 参数生成共享链接。
2、CLI推理
使用 f5-tts_infer-cli 命令进行命令行推理。 需要指定模型名称 (–model)、参考音频路径 (–ref_audio)、参考文本 (–ref_text) 和要生成的文本 (–gen_text)。 可以使用配置文件 (-c) 指定参数。 支持多语音生成。
# Launch a Gradio app (web interface)f5-tts_infer-gradio# Specify the port/hostf5-tts_infer-gradio --port 7860 --host 0.0.0.0# Launch a share linkf5-tts_infer-gradio --share
模型文件下载可能出现连接超时等网络问题
- 访问模型文件镜像站
https://huggingface.co/SWivid/F5-TTS
- 访问国内镜像站
https://hf-mirror.com/
方法:huggingface-cli
huggingface-cli 是 Hugging Face 官方提供的命令行工具,自带完善的下载功能。
- 安装依赖
pip install -U huggingface_hub
- 设置环境变量
- Linux
export HF_ENDPOINT=https://hf-mirror.com
- 使用文本编辑器以管理员权限打开/etc/environment文件。你可以使用nano或者vim。例如,使用nano的命令如下:
- sudo nano /etc/environment
- 在文件中添加你的环境变量。在你的情况下,添加这行:
HF_ENDPOINT=\"https://hf-mirror.com\"
- 保存并关闭文件。如果你使用的是nano,可以通过按Ctrl+X,然后按Y确认保存,最后按Enter键来保存文件。
- 为了使变更立即生效,你可以注销并重新登录,或者在终端中运行以下命令来重载环境变量:
source /etc/environment
这样,HF_ENDPOINT环境变量就被设置为永久的了,并且每次启动时都会自动加载。
3.1 下载模型示例
huggingface-cli download --resume-download SWivid/F5-TTS --local-dir /home/x1/F5-TTS/ckpts/
3.2 下载数据集示例
huggingface-cli download --repo-type dataset --resume-download wikitext --local-dir wikitext
可以添加 --local-dir-use-symlinks False 参数禁用文件软链接,这样下载路径下所见即所得,详细解释请见上面提到的教程。
5.启动Gradio应用 (Web界面)
- 命令
f5-tts_infer-gradio --port 13066 --host 0.0.0.0
6.编写一个Python推理的Flask接口程序
import refrom flask import Flask, request, jsonify, send_fileimport ioimport tempfileimport soundfile as sfimport osfrom f5_tts.infer.utils_infer import ( preprocess_ref_audio_text, infer_process, remove_silence_for_generated_wav)from f5_tts.model import DiTfrom f5_tts.infer.utils_infer import load_vocoder, load_modelapp = Flask(__name__)# Paths to model and vocab filesMODEL_PATH = \"/home/x1/F5-TTS/ckpts/F5TTS_Base/model_1200000.safetensors\"VOCAB_PATH = \"/home/x1/F5-TTS/ckpts/F5TTS_Base/vocab.txt\"# Initialize TTS model and vocoderF5TTS_ema_model = Nonevocoder = load_vocoder()def load_f5tts_model(): global F5TTS_ema_model if F5TTS_ema_model is None: F5TTS_model_cfg = dict(dim=1024, depth=22, heads=16, ff_mult=2, text_dim=512, conv_layers=4) F5TTS_ema_model = load_model(DiT, F5TTS_model_cfg, MODEL_PATH, vocab_file=VOCAB_PATH)load_f5tts_model()def convert_to_chinese_date_bak(text): print(\" 数字和日期转换操作...\") \"\"\"Convert dates and numbers in the text to Chinese format.\"\"\" num_map = { \"0\": \"零\", \"1\": \"一\", \"2\": \"二\", \"3\": \"三\", \"4\": \"四\", \"5\": \"五\", \"6\": \"六\", \"7\": \"七\", \"8\": \"八\", \"9\": \"九\"} def number_to_chinese(match): number = match.group() if len(number) == 1: # 单个数字 return num_map[number] elif len(number) == 2: # 两位数 if number.startswith(\"1\"): # 特殊处理10-19 return \"十\" + (num_map[number[1]] if number[1] != \"0\" else \"\") else: return num_map[number[0]] + \"十\" + (num_map[number[1]] if number[1] != \"0\" else \"\") else: return \"\".join(num_map[digit] for digit in number) # 处理三位及以上的数字 # 将日期格式(如12月、10日)处理为中文读法 text = re.sub(r\'\\d+\', number_to_chinese, text) return text# 0–9 的汉字对照表digit_map = \"零一二三四五六七八九\"def int_to_chinese(n: int) -> str: \"\"\" 把 0–9999 的整数转换成口语中文: 0 → 零 7 → 七 10 → 十 15 → 十五 20 → 二十 105 → 一百零五 5000 → 五千 \"\"\" assert 0 <= n < 10000, \"当前版本仅支持 0–9999\" if n == 0: return \"零\" units = [\"\", \"十\", \"百\", \"千\"] parts = [] digits = list(map(int, str(n))) # 逆序遍历,每次插入“千百十”单位 for idx, d in enumerate(reversed(digits)): if d == 0: if parts and parts[-1] != \"零\": # 连续零只插一个 parts.append(\"零\") else: parts.append(units[idx]) parts.append(digit_map[d]) s = \"\".join(reversed(parts)).rstrip(\"零\") # 去掉末尾可能残留的零 return s.replace(\"一十\", \"十\") if n < 100 else s # 10–19:省略“一”def convert_date(match: re.Match) -> str: year, month, day = match.groups() year_cn = \"\".join(digit_map[int(d)] for d in year) month_cn = int_to_chinese(int(month)) day_cn = int_to_chinese(int(day)) return f\"{ year_cn}年{ month_cn}月{ day_cn}日\"decimal_pat = re.compile(r\"\\d+\\.\\d+\")date_pat = re.compile(r\"(\\d{4})年(\\d{1,2})月(\\d{1,2})日\")integer_pat = re.compile(r\"\\d+\")def convert_decimal(match: re.Match) -> str: integer, fraction = match.group().split(\".\") int_cn = int_to_chinese(int(integer)) frac_cn = \"\".join(digit_map[int(d)] for d in fraction) return f\"{ int_cn}点{ frac_cn}\"def convert_to_chinese(text: str) -> str: \"\"\"把字符串中的数字 / 日期转换为中文口语读法。\"\"\" # ① 小数 text = decimal_pat.sub(convert_decimal, text) # ② 完整日期 text = date_pat.sub(convert_date, text) # ③ 剩余纯整数 text = integer_pat.sub(lambda m: int_to_chinese(int(m.group())), text) return text@app.route(\'/generateAudio\', methods=[\'POST\'])def synthesize(): # Validate and parse input if \'gen_text\' not in request.form: return jsonify({ \"error\": \"Missing required parameter: \'gen_text\'\"}), 400 gen_text = request.form[\'gen_text\'] ref_text = request.form.get(\'ref_text\', \'\') ref_audio_path = None if \'ref_audio\' in request.files: # Save uploaded reference audio file to a temporary location ref_audio = request.files[\'ref_audio\'] with tempfile.NamedTemporaryFile(delete=False, suffix=\".wav\") as temp_audio_file: ref_audio.save(temp_audio_file.name) ref_audio_path = temp_audio_file.name elif \'ref_audio_path\' in request.form: # Use reference audio path provided in the form ref_audio_path = request.form[\'ref_audio_path\'] if not os.path.exists(ref_audio_path): return jsonify({ \"error\": f\"File not found: { ref_audio_path}\"}), 400 if not ref_audio_path: return jsonify({ \"error\": \"Missing required parameter: \'ref_audio\' or \'ref_audio_path\'\"}), 400 try: # Convert dates in gen_text to Chinese format gen_text = convert_to_chinese(gen_text) # Preprocess reference audio and text ref_audio_data, ref_text = preprocess_ref_audio_text(ref_audio_path, ref_text) # Synthesize speech final_wave, final_sample_rate, _ = infer_process( ref_audio_data, ref_text, gen_text, F5TTS_ema_model, vocoder, cross_fade_duration=0.15, speed=1.0, ) # Remove silences from generated audio with tempfile.NamedTemporaryFile(delete=False, suffix=\".wav\") as temp_generated_audio: sf.write(temp_generated_audio.name, final_wave, final_sample_rate) remove_silence_for_generated_wav(temp_generated_audio.name) final_wave, _ = sf.read(temp_generated_audio.name) # Convert synthesized audio to bytes audio_buffer = io.BytesIO() sf.write(audio_buffer, final_wave, final_sample_rate, format=\'WAV\') audio_buffer.seek(0) return send_file( audio_buffer, as_attachment=True, download_name=\"synthesized_audio.wav\", mimetype=\"audio/wav\" ) except Exception as e: return jsonify({ \"error\": str(e)}), 500if __name__ == \'__main__\': app.run(host=\'0.0.0.0\', port=13666, debug=True)
- 注意在读取日期时候会出错,这个地方可以编写一个日期处理函数来解决这个问题。
6.1 启动语音合成的推理程序
- 进入Python虚拟环境
source /home/x1/anaconda3/bin/activateconda activate f5-tts
- 进入程序所在的目录,运行并挂起程序,输出日志到日志文件
# 进入程序所在的目录cd /home/x1/F5-TTS/src/f5_tts/infer/# 运行并挂起程序,输出日志到日志文件nohup python tts_api.py >> ./tts_api.log &
7.使用go语言编写一个合成声音的接口
- 创建F5_TTSGenerateAudio.go文件