Fish Speech-1.5语音合成提效工具Markdown文档自动转语音脚本你是不是也遇到过这样的场景一份精心撰写的技术文档、产品说明或者学习笔记想让团队成员或者用户能“听”到而不是只能“看”。手动录制音频费时费力还容易出错。找专业配音成本高昂不灵活。今天我就来分享一个能让你彻底告别这些烦恼的自动化工具一个基于Fish Speech-1.5语音合成模型的Markdown文档自动转语音脚本。它能一键将你的Markdown文档转换成自然、流畅的语音无论是中文、英文还是其他十几种语言都能轻松搞定。1. 为什么需要文档转语音在开始动手之前我们先聊聊为什么这个工具如此有用。想象一下这些场景技术分享你写了一篇技术博客想做成播客分享给通勤路上的开发者。产品文档你的产品有详细的使用手册想为视力障碍用户或喜欢“听”的用户提供音频版本。学习材料你整理了一份学习笔记想在运动、做家务时“听”着复习。内容多平台分发一份内容既想发布成文章也想同步到音频平台如喜马拉雅、小宇宙。传统方法要么依赖人工录制成本高、效率低要么使用机械的TTS引擎声音生硬、不自然。而我们的方案结合了强大的Fish Speech-1.5模型能生成媲美真人、富有表现力的语音再通过自动化脚本将整个过程变得像保存文件一样简单。2. 核心引擎Fish Speech-1.5 语音合成模型这个工具的核心是Fish Speech-1.5一个非常出色的开源文本转语音模型。在开始写脚本前我们需要先把它部署起来。2.1 Fish Speech-1.5 是什么简单来说它是一个“声音魔法师”。你给它文字它就能还你一段自然流畅的语音。它的厉害之处在于海量训练基于超过100万小时的多语言音频数据训练而成声音质量很高。多语言支持直接支持13种语言无需额外配置。这对于国际化内容创作来说简直是福音。支持语言训练数据量约说明英语 (en)300k 小时发音纯正适用性广中文 (zh)300k 小时普通话标准音色自然日语 (ja)100k 小时适合动漫、技术文档配音德语 (de)~20k 小时法语 (fr)~20k 小时西班牙语 (es)~20k 小时韩语 (ko)~20k 小时阿拉伯语 (ar)~20k 小时俄语 (ru)~20k 小时荷兰语 (nl)10k 小时意大利语 (it)10k 小时波兰语 (pl)10k 小时葡萄牙语 (pt)10k 小时易于部署我们可以通过Xinference框架快速部署成服务通过简单的API来调用。2.2 使用 Xinference 快速部署模型部署是使用的第一步。这里我们选择Xinference (2.0.0)它是一个强大的模型推理和服务框架能让部署变得非常简单。步骤简述启动模型服务通常一行命令就能在服务器或本地启动Fish Speech-1.5模型。检查服务状态部署后查看日志确认模型是否加载成功。cat /path/to/your/model_server.log当你看到模型加载完成、服务正常启动的日志信息时就说明成功了。访问Web UIXinference通常会提供一个图形化界面。在服务器上找到对应的访问地址例如http://你的服务器IP:端口点击进入。测试合成在Web UI里你可以直接输入文本点击“生成语音”立即试听效果。这是验证部署是否成功最直观的方式。一旦Web UI测试成功就意味着我们的“声音魔法师”已经准备就绪可以通过API来为我们工作了。3. 自动化脚本让转换一键完成Web UI好用但每次都要手动复制粘贴文本效率太低。我们的目标是自动化。下面就是这个工具的核心——Python脚本。这个脚本主要做三件事读取读取你的Markdown文件。处理清理文本将其分割成适合合成的段落。合成与保存调用Fish Speech-1.5的API生成语音并保存为MP3文件。3.1 脚本核心代码解析我们来一步步拆解这个脚本的关键部分。首先安装必要的Python库pip install requests markdown然后是脚本的主体 (markdown_to_speech.py)import requests import re import os from pathlib import Path class MarkdownToSpeech: def __init__(self, base_urlhttp://localhost:9997, languagezh): 初始化转换器 :param base_url: Xinference 模型服务的地址 :param language: 语音合成的语言如 zh(中文), en(英文) self.base_url base_url.rstrip(/) self.language language self.api_url f{self.base_url}/v1/audio/speech def clean_markdown_text(self, text): 清理Markdown文本移除标记符号提取纯文本。 # 移除图片标记  text re.sub(r!\[.*?\]\(.*?\), , text) # 移除链接标记 [text](url) text re.sub(r\[(.*?)\]\(.*?\), r\1, text) # 移除代码块标记 language ... text re.sub(r.*?, , text, flagsre.DOTALL) # 移除行内代码标记 code text re.sub(r([^]), r\1, text) # 移除标题标记 #, ## text re.sub(r^#\s*, , text, flagsre.MULTILINE) # 移除粗体、斜体标记 **bold** *italic* text re.sub(r\*\*(.*?)\*\*, r\1, text) text re.sub(r\*(.*?)\*, r\1, text) # 移除列表标记 -, *, 1. text re.sub(r^[\s]*[-*]\s, , text, flagsre.MULTILINE) text re.sub(r^[\s]*\d\.\s, , text, flagsre.MULTILINE) # 移除多余的空白行和首尾空格 lines [line.strip() for line in text.splitlines() if line.strip()] cleaned_text \n.join(lines) return cleaned_text def split_into_chunks(self, text, max_chunk_length300): 将长文本分割成适合TTS模型处理的段落。 按句号、问号、感叹号分割并确保每段不超过最大长度。 # 首先按句子分割 sentence_endings re.compile(r([。\.\?!;]\s*)) parts sentence_endings.split(text) chunks [] current_chunk for i in range(0, len(parts)-1, 2): sentence parts[i] (parts[i1] if i1 len(parts) else ) # 如果当前句子本身就超过最大长度则按字数硬切分应尽量避免 if len(sentence) max_chunk_length: # 先保存已有的段落 if current_chunk: chunks.append(current_chunk.strip()) current_chunk # 将长句子按字数切分 for start in range(0, len(sentence), max_chunk_length): end start max_chunk_length chunk sentence[start:end] if chunk.strip(): chunks.append(chunk.strip()) else: # 如果加上新句子后长度超标则保存当前段落开始新段落 if len(current_chunk) len(sentence) max_chunk_length: if current_chunk.strip(): chunks.append(current_chunk.strip()) current_chunk sentence else: current_chunk sentence # 添加最后一个段落 if current_chunk.strip(): chunks.append(current_chunk.strip()) return chunks def text_to_speech(self, text, output_pathoutput.mp3): 调用Fish Speech-1.5 API将文本合成为语音。 headers { Content-Type: application/json } # 构造符合Xinference /v1/audio/speech 接口的请求数据 data { model: fish-speech-1.5, # 模型名称根据实际部署调整 input: text, language: self.language, # 可以根据需要添加更多参数如 voice音色、speed语速等 # voice: default, # speed: 1.0, } try: response requests.post(self.api_url, jsondata, headersheaders, streamTrue) response.raise_for_status() # 检查请求是否成功 # 保存音频文件 with open(output_path, wb) as f: for chunk in response.iter_content(chunk_size8192): f.write(chunk) print(f✅ 语音文件已保存至: {output_path}) return True except requests.exceptions.RequestException as e: print(f❌ 请求API失败: {e}) return False except Exception as e: print(f❌ 保存文件时出错: {e}) return False def convert_file(self, md_file_path, output_diraudio_output): 主函数转换单个Markdown文件。 # 读取Markdown文件 try: with open(md_file_path, r, encodingutf-8) as f: md_content f.read() except Exception as e: print(f❌ 无法读取文件 {md_file_path}: {e}) return print(f 正在处理文件: {md_file_path}) # 1. 清理文本 clean_text self.clean_markdown_text(md_content) if not clean_text: print(⚠️ 文件内容为空或清理后无有效文本。) return # 2. 分割文本 text_chunks self.split_into_chunks(clean_text) print(f 文本已分割为 {len(text_chunks)} 个段落。) # 3. 准备输出目录 Path(output_dir).mkdir(parentsTrue, exist_okTrue) base_name Path(md_file_path).stem # 4. 分段合成语音避免单次请求文本过长 audio_files [] for i, chunk in enumerate(text_chunks): if not chunk.strip(): continue print(f 正在合成段落 {i1}/{len(text_chunks)}...) chunk_output_path os.path.join(output_dir, f{base_name}_part_{i1:03d}.mp3) if self.text_to_speech(chunk, chunk_output_path): audio_files.append(chunk_output_path) else: print(f 段落 {i1} 合成失败跳过。) print(f 转换完成共生成 {len(audio_files)} 个音频文件位于目录 {output_dir} 中。) # 此处可以添加音频文件合并的代码如需生成单个文件 # self.merge_audio_files(audio_files, os.path.join(output_dir, f{base_name}_full.mp3)) if __name__ __main__: # 使用示例 converter MarkdownToSpeech( base_urlhttp://你的服务器IP:端口, # 替换为你的Xinference服务地址 languagezh # 中文合成 ) # 转换单个文件 converter.convert_file(你的文档.md, output_dir我的音频)3.2 脚本使用指南配置修改脚本底部main部分的base_url指向你部署好的Xinference服务地址。运行在命令行中执行python markdown_to_speech.py。查看结果脚本会在指定的output_dir目录下为你的Markdown文档生成对应的MP3音频文件并按段落分割。脚本做了哪些智能处理文本清洗自动过滤掉Markdown的语法标记如#、**、![图片]()只提取可读的纯文本。智能分段不会粗暴地按固定字数切割而是优先按句子结束符。分割保证每个音频段落的语义完整性听起来更自然。错误处理网络请求失败、文件读写错误等都有相应处理避免程序意外崩溃。4. 进阶玩法与优化建议基础的转换功能有了我们还可以让它变得更强大、更好用。4.1 功能扩展思路批量处理修改脚本使其能遍历一个文件夹内的所有.md文件实现批量转换。音色与语速调节研究Fish Speech-1.5的API看是否支持指定音色、调节语速或情感将这些参数加入到脚本的配置选项中。音频后处理转换完成后自动为每段音频添加淡入淡出效果或者将所有分段合并成一个完整的、带有章节标记的有声书。集成到工作流将这个脚本与你的文档编译流程比如用MkDocs、Docsify构建文档站结合实现“文档更新语音自动同步生成”。4.2 效果优化技巧文本预处理对于技术文档代码块直接念出来体验很差。脚本目前是移除代码块你可以选择优化为在音频中插入提示音或生成一个单独的“代码说明”音频文件。分段策略调优max_chunk_length参数需要根据实际模型的表现调整。太长可能导致合成慢或出错太短则语音不连贯。300-500字通常是个不错的起点。元数据注入生成音频文件时可以利用mutagen这样的库将文章标题、作者等信息写入MP3文件的ID3标签中。5. 总结通过将Fish Speech-1.5强大的语音合成能力与一个简单的Python自动化脚本相结合我们成功构建了一个高效的“Markdown文档转语音”工具。这个方案的优势非常明显质量高借助顶级开源TTS模型语音自然度远超传统机械音。效率高全自动处理从文档到音频一键完成。成本低基于开源模型和脚本部署后边际成本几乎为零。可定制脚本完全由你掌控可以根据具体需求任意修改和扩展。无论是用于内容创作、知识管理还是无障碍支持这个工具都能显著提升你的工作效率。现在你可以让每一份有价值的文字都拥有自己的“声音”。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。