尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

银河麒麟V10离线语音合成:从零部署EKHO文本转语音全攻略

发布时间:2026/9/29 7:28:51

资讯中心
01
ARTICLE

银河麒麟V10离线语音合成:从零部署EKHO文本转语音全攻略

银河麒麟V10离线语音合成:从零部署EKHO文本转语音全攻略
单位那批银河麒麟V10终端刚替换到位的时候办公室里最热闹的话题是“能不能正常办公”。我这边倒无所谓文档表格那套真正让我头疼的是另一件事文本转语音。之前在一套老旧系统上做运维监控播报、批量语音提示靠的是Windows上的一个工具到了国产平台直接废掉。后来在开源社区里翻到 EKHO余音才算把这根弦接上。这篇文章就围绕“EKHO 文本转语音 银河麒麟V10”这条线把我从零开始部署、调参、踩坑到最终跑进工作流的全过程完整写出来给同样在信创终端上做语音方案的朋友一个可参考的样本。1. 余音EKHO到底是什么一个被忽略的离线中文TTS老兵先把这个工具讲清楚。EKHO中文名叫“余音”是一个基于拼接合成思路的开源文本转语音引擎作者是刘斌华。它从诞生到现在走了一条和现在主流神经TTS完全不同的路线不依赖GPU不依赖Python那一大堆推理框架也不需要在推理时加载几GB的模型权重。它把普通话、粤语、闽南语乃至日语等语音的发音单元预先录制、切分并建立索引合成时按文本切出的音节序列去“查表拼接”再用信号处理算法对拼接点做平滑和韵律修饰输出相对自然的连续语音。拿个生活中的例子类比现代神经TTS相当于一个演员拿到剧本后临场发挥每一句话都是全新演绎效果上限高但吃配置EKHO更像一个电台剪辑师素材库里存着海量字词录音片段你说“你好”他就把“你”和“好”两段录音拼起来再做点音调、时长上的润色。这种做法的好处非常明显启动快常驻内存占用通常只有几十到一两百MB纯CPU就能实时合成离线环境完全可用。正是这些特征让EKHO在银河麒麟V10这类国产化终端上显得格外“对症”。信创终端的特点是配置普遍不高很多还是ARM架构使用场景又常常在政务内网或企业隔离网没有外网去下载模型权重和依赖包也不可能每台机器都配一块中高端GPU。这种情况下EKHO这种把依赖锁死在几组动态库上的轻量级TTS反而是最不容易翻车的方案。从能力边界上讲EKHO适合以下几类典型用途运维监控语音播报脚本检测到异常后把告警文本合成为wav文件再调用播放器输出。定时提醒与语音公告在值班室、大厅屏幕上循环播报通知。短文本信息服务把天气、挂号、排号等结构化文本转成语音。辅助工具为读屏场景或语音提示类小应用提供离线语音支持。主要局限性是长文本自然度一般尤其整段朗读小说、演讲稿时会显得机械。这不是它设计上要解决的问题明白这一点选型时就不会误判。另外它对标点符号、数字、英文单词的处理需要我们在文本层面做预处理这一点我后面专门用一个章节讲。2. 银河麒麟V10环境审视先摸清系统的“底细”再动手在银河麒麟V10上跑任何开源软件第一步不是急着下载编译而是把系统的“底细”摸清楚。银河麒麟V10的发行分支情况有点特殊桌面版和服务器版底子不一样不同SP版本也对应不同的包管理体系和基础库版本。要是没搞清楚就套用网上的命令大概率会白折腾。先执行下面几条命令把系统身份和架构确认清楚cat /etc/os-release uname -m lscpu | grep Architecture这里有个常见认知误区很多人以为银河麒麟V10只有“基于Debian”一个版本其实正式环境里还存在基于CentOS兼容分支的版本。两者包管理器一个用apt一个用yum/dnf源列表和依赖包的命名都有差异。你要是拿apt去跑一个yum体系的系统第一关就卡住。架构方面也要重点确认。银河麒麟V10终端在党政办公领域常见飞腾FT-2000系列、腾锐D2000系列、鲲鹏920这些ARM芯片部分市场化项目会用x86_64的intel/amd平台。EKHO本身对ARM的支持做得不错源码编译基本无障碍但前提是你下载的源码包和依赖库版本、交叉编译选项要和架构匹配。确认完这些之后还要快速检查一下系统中是否已经存在部分依赖组件避免重复折腾。比较重要的是音频服务状态systemctl --typeservice | grep -E pipewire|pulseaudio aplay -l早期银河麒麟桌面版音频服务以PulseAudio为主后来一些新版本迁移到了PipeWire。两者的总线接口不完全一样如果EKHO编译时锁定了PulseAudio的客户端库却在纯PipeWire环境运行播放环节可能无声。这一点先记住后面有专门章节讲排查链路。我建议在系统里专门为这个项目建一个普通用户不要直接用root跑频繁的TTS调用。原因有二一是合成任务如果被恶意脚本或者异常文本反复触发可能产生大量文件读写二是很多合成引擎在root下反而容易遇到安全策略限制。实际工作中我用一个叫tts的普通用户承载这套服务。还有一个很容易被忽视的点磁盘布局。如果你打算把生成的wave文件集中存放建议放到独立的数据分区并在系统安装或迁移阶段就规划好。热搜词里有一条“微信文件管理安装路径 银河麒麟桌面操作系统V10 数据盘路径”说明很多人踩过“默认分区被写满”的坑。我这边更夸张的是某台机器首次执行批量语音合成时因为输出文件没有重定向直接把根分区/顶到了98%。后面我做了两件事输出目录统一挂到/data/tts_output同时给合成脚本加磁盘阈值检查低于5%可用空间就发告警。3. 从源码到能发声EKHO在V10上的完整部署路径EKHO在很多主流发行版仓库里都有包但银河麒麟V10的默认源里并没有收录所以推荐走源码编译这条路。整个流程不复杂但每个步骤都有值得记录的细节。3.1 依赖准备缺什么就补什么先安装编译工具链和运行时依赖。以基于Debian的银河麒麟桌面V10为例sudo apt update sudo apt install -y build-essential autoconf automake libtool pkg-config sudo apt install -y libespeak-dev libpulse-dev libsndfile1-dev libncurses5-dev逐个说一下为什么要这几个包libespeak-devEKHO的历史版本里部分语言比如英语、粤语可以借助eSpeak做规则合成或后备发音同时也是中文无声调音节拆分的辅助参考。虽然主合成走的是自有录音库但编译期还是依赖这个头文件。libpulse-devPulseAudio客户端库负责把合成好的PCM数据送进声卡。如果你的系统是PipeWire并提供了libpulse兼容层这个包仍然适用。libsndfile1-dev用于读写wav等音频文件格式合成落盘的关键依赖。libncurses5-dev终端交互界面的支持库编译时会用到。如果你是CentOS兼容分支的系统命令换成sudo yum install -y gcc gcc-c make autoconf automake libtool pkgconfig sudo yum install -y espeak-devel pulseaudio-libs-devel libsndfile-devel ncurses-devel依赖装完之后建议顺手执行一次ldconfig然后立刻验证一下关键库是否就位避免编译到一半才发现缺东西ldconfig -p | grep -E libpulse|libsndfile|libespeak3.2 下载与编译不要跳步configure输出要逐行看从开源社区获取EKHO源码包解压后进入目录。我的操作习惯是任何开源项目都先读README和INSTALL确认作者推荐的编译方式再执行命令。EKHO的经典编译路径是autotools链tar zxf ekho-*.tar.gz cd ekho-* ./configure --prefix/usr/local这里补充一个重要信息./configure阶段会打印检测结果重点看这几行有没有被标记成“no”——PulseAudio、libsndfile、eSpeak。如果在终端上看到某个重要依赖标记为no不要急着往下走回头补装对应的-dev包再重跑configure。很多人编译失败根源就是这个阶段没盯紧后面make报错才回头找原因来回折腾。确认无误后正式编译安装make -j4 sudo make install sudo ldconfig-j4是让4个编译任务并行执行如果是飞腾D2000这类8核机器可以调整到-j8缩短等待时间。编译完成后检查一下安装结果which ekho ekho --version这一步如果报找不到命令说明/usr/local/bin没有进PATH。可以用export PATH$PATH:/usr/local/bin临时解决写到~/.bashrc里永久生效。3.3 安装语音数据声音素材和主程序是分离的这是EKHO使用中最容易出岔子的环节主程序装上不代表能说话它还需要一套语音数据文件也就是前面说的“预录语音单元库”。普通话语音数据由额外的数据包提供通常体积几十MB到上百MB不等。数据包要解压到程序约定好的目录一般是/usr/share/ekho/。安装完成后用一行命令验证ekho 你好银河麒麟如果耳机或音箱里传来清晰的“你好银河麒麟”说明主程序、数据包、音频服务三条链路都是通的。如果无声先不要怀疑是数据包问题跳到后面的排查章节看。验证通过后再测一下落盘合成ekho -o /tmp/test.wav 文本转语音测试 ls -lh /tmp/test.wav aplay /tmp/test.wav-o参数指定输出wav文件aplay是Linux标准的命令行播放器。我习惯用这两步组合来验证TTS服务是否正常的因为直接播放考验声卡链路落盘测试考验文件I/O和音频编码两个都过基本可以判断工具本身没问题。这里的细节价值在于源码编译这条路虽然比“一键安装”多几步但你对系统的掌控感完全不同。出了问题时你能清楚地知道自己在哪一层而不是在一个装好的黑盒面前发呆。4. 动手前的基本功写入文本的预处理规则与输出参数EKHO不是把中文文本丢进去就万事大吉它的文本前端处理逻辑相对朴素。无论是命令行调用还是后续写脚本都需要先把中文文本规整好。4.1 数字、字母、单位的转写规则拼接合成引擎没有类似神经TTS内部的“数字-汉字读音”自动转换模块。直接输入“2024年产量是12345件”它可能把“2024”按不连续的数字逐个读出来听起来像“二零一零一四”而不是“二零二四年”或“两千零二十四年”。因此我每次在调用合成之前会先做一层正则替换。以下是我在Python脚本中常用的预处理函数片段import re def normalize_zh_text(text): # 常见中文标点统一为句读 text re.sub(r[,], , text) text re.sub(r[。.], 。, text) text re.sub(r[;], , text) # 年份2024年 - 二零二四年也可以转成“两千零二十四年”看习惯 text re.sub(r(\d{4})年, lambda m: digit_to_cn(m.group(1)) 年, text) # 纯数字按数值读法处理加亿/万等单位 text re.sub(r(\d{2,}), lambda m: num_to_cn(m.group(1)), text) # 百分号 text text.replace(%, 百分之) text text.replace(, 百分之) # 英文单词统一转音译或按字母读这里按简单方案处理 text re.sub(r[A-Za-z], lambda m: .join(list(m.group(0).upper())), text) return text这里我提一个原则数字转写不用追求绝对完美TTS场景大多是播报通知、告警信息听众关注的是速度和准确性。对公文中经常出现的“3.14”“1234567890”建议在文本层就转成“三点一四”“十二亿三千四百五十六万七千八百九十”效果会好很多。4.2 多音字与自定义发音中文多音字是拼接TTS的另一个痛点。“重庆”如果按默认音库拼很可能读成“重zhòng庆”“会计”可能读成“会huì计”。EKHO引入了自定义拼音注解机制可以在文本中使用拼音标记直接指定发音。内置的拼音输入采用的是带声调的拼音字符串。例如ekho chong2 qing4 市今天天气不错这里chong2表示“重”读第二声qing4表示“庆”读第四声。注意发音与汉字之间用空格隔开多音节词的每个音节都要标注。如果某个字不想用文本直接给拼音就行合成器会跳过汉字解析过程并按给定音素拼接。这个能力相当实用避开了很多拼接引擎的“读错字”尴尬。4.3 声音参数调节EKHO的命令行参数设计得比较精简关键参数如下参数作用取值范围参考说明-v选择语言/发音人zh, yue, hakka, jp, en等默认zh普通话-s语速调整一般0.5~1.5之间小于1变慢大于1变快-p音调调整一般0.5~1.5之间调高调低音调-a音量增益0~200100为原音量-o输出wav文件文件路径不指定则直接播放-f从文件读取文本文件路径适合长文本批量合成-t每次合成后的静音间隔毫秒常用于长文本分段合成实际使用中我固定用这样一组参数组合ekho -v zh -s 1.0 -p 1.1 -a 120 -o /data/tts_output/notice.wav 这是一条离线语音合成测试为什么把-p调到1.1因为拼接合成的声音普遍偏低沉略微上调一点音调会让人觉得发音更清晰尤其在广播喇叭这类频响一般的设备上中高频提上来之后可懂度明显改善。这个参数没有标准答案建议在自己的设备上多试几组找到最适合的那档。5. 把TTS跑进真实工作流脚本化、批量合成与服务化一个命令行工具如果永远只在终端里手动敲价值有限。下面分享我实际建成并稳定跑了一段时间的几种工作流形态可以直接复制改改。5.1 告警文本自动播报运维告警场景是我用得最多的。Nagios、Zabbix这类监控系统能触发脚本动作我用一个简单的bash脚本接收告警内容合成语音并播放到值班室音箱#!/bin/bash ALERT_TEXT$1 TMPWAV$(mktemp --suffix.wav) # 文本预处理后合成 echo $ALERT_TEXT | perl -pe s/%/百分之/g /tmp/alert_norm.txt /usr/local/bin/ekho -f /tmp/alert_norm.txt -o $TMPWAV # 播放并通过系统音量控制放大播报 playerpaplay $player $TMPWAV # 清理临时文件 rm -f $TMPWAV /tmp/alert_norm.txt这里有个细节不要直接在原文本上合成因为监控系统推送的消息里经常含有百分号、等于号、IP地址等特殊字符要先做一轮清洗。上面脚本用perl把%替换成“百分之”实际使用里还要视告警类型把IP地址转成“幺九二点幺六八点壹点壹零”这种读法否则会非常难听。5.2 批量语音文件生成做语音机器人时需要预先合成一批常用语音文件作为资源库而不是每次实时合成。这个时候用文件循环批量生成cd /data/tts_scripts cat phraselist.txt | while IFS read -r phrase; do fname$(echo $phrase | md5sum | cut -d -f1) /usr/local/bin/ekho -o /data/tts_lib/${fname}.wav $phrase done用md5sum生成文件名是个小技巧可以保证同样的文本只生成一次避免重复占用磁盘。总文件多的情况下建议分几次批量生成避免一次跑太久音库访问出现异常。5.3 定时任务里的语音服务定时播报我一般交给crontab处理。下面是一个每天早晨8点播报当日日程的例子0 8 * * * /usr/local/bin/ekho -o /tmp/schedule.wav 今天是星期三上午九点有项目例会请大家准时参加; paplay /tmp/schedule.wav这只是最简单的形态。实际使用时我更喜欢写成一个独立服务脚本先从一个JSON文件读取当日日程格式化后用Python调用预处理函数清好文本再走EKHO合成播放最后把播放结果和异常记录到日志文件。这样即使合成失败也能追查哪一步出了问题。5.4 Web接口封装如果需要给其他部门提供TTS能力一个轻量的HTTP接口更方便。我用Python的Flask框架写了个不到30行的接口对外暴露/tts服务其他系统只要POST一段文本就能拿到wav文件或播放流。核心代码如下from flask import Flask, request, send_file import subprocess, uuid, os app Flask(__name__) app.route(/tts, methods[POST]) def tts(): data request.get_json() text data.get(text, ) if not text: return no text, 400 wav_path f/tmp/{uuid.uuid4().hex}.wav subprocess.run([/usr/local/bin/ekho, -o, wav_path, text], checkTrue) return send_file(wav_path, mimetypeaudio/wav)注意在实际部署时要加上鉴权、并发控制、文件清理机制毕竟服务暴露后任何人都能调用的话磁盘会被撑爆。并发控制我采用了目录锁加队列的方式稳定运行了很久。6. 实测中最容易踩的几个坑从无声到乱码的完整排查链路这段是整个博文里我最想写的部分。工具本身不难难的是出了问题后怎么一步步定位。下面三个坑我都在银河麒麟V10上真实遇到过按排查思路完整写出来不走捷径。6.1 合成正常却无声音频链路排查症状命令行执行ekho 你好没有报错但音响没有任何声音。不要急着怀疑EKHO先绕开它用系统自带的工具检查音频链路。完整链路如下# 1. 检查声卡是否被系统识别 aplay -l # 2. 检查音频服务进程是否存在 ps -ef | grep -E pipewire|pulseaudio # 3. 用系统工具直接播放绕过TTS speaker-test -t wav -c 2 # 4. 用paplay播放已有wav paplay /tmp/test.wav如果speaker-test或paplay同样无声问题在系统音频层排除EKHO。这时继续往深处走aplay -l没有输出或返回错误说明驱动层没起来重点查固件和ALSA配置。进程里没有PulseAudio或PipeWire说明音频服务没启动执行systemctl --user start pipewire pipewire-pulse或者pulseaudio --start。服务都在但无声检查音量pactl list sinks | grep -A 10 State: RUNNING pactl set-sink-volume DEFAULT_SINK 80%如果aplay -l正常、系统播放也正常而EKHO合成无输出这时才把目光放回EKHO的音频后端参数。EKHO在编译和运行时有一个关键的音频输出方式选择点默认走libpulse如果你的环境恰好是PipeWire且libpulse兼容层有问题可以改用ALSA直接输出。具体做法是检查系统是否安装了libasound2-dev重新编译EKHO时启用对应选项或者运行时指定音频设备。6.2 中文变成歪歪扭扭的乱码音语音数据包和编码问题症状ekho hello能正常读出英文但ekho 你好发出来的是不连续的外星音或干脆读错。这个表现通常不是“不能发声”而是“中文语音数据没有正确加载”。按这个顺序排查# 1. 确认普通话数据包是否安装到了正确位置 ls -l /usr/share/ekho/ # 2. 确认数据目录里有没有Mandarin、Pinyin相关的库文件 find /usr/share/ekho -type f | head -30 # 3. 查看环境变量是否被意外覆盖 echo $EKHO_DATA_DIR标准安装下普通话数据文件应该存在于/usr/share/ekho/下。如果目录为空或只有部分文件把数据包完整解压进去再试。另外还要确认当前终端的locale是否支持UTF-8echo $LANG应该包含zh_CN.UTF-8或en_US.UTF-8。文本输入编码问题也容易混淆如果你的Python脚本或Shell脚本里硬编码了GBK编码的中文而EKHO按UTF-8解析那么出来的就是一团乱码。所有调用EKHO的脚本文本变量一律用UTF-8必要时在脚本开头写export LANGzh_CN.UTF-8。6.3 源码编译失败缺头文件和架构适配问题最常见的编译失败原因就是依赖头文件缺失。典型报错是fatal error: pulse/pulseaudio.h: No such file or directory。这一般直接对应没有安装libpulse-dev。解决思路非常直接把前面依赖列表里的-dev包全部补上重新configure。configure阶段多拿几分钟仔细读输出能省后面一小时的排错时间。ARM架构下还有一个容易忽略的点如果你拿到的源码包是老版本而系统里某些库版本较新可能会遇到函数签名不匹配的问题。例如老代码调用pa_simple_new时的参数结构和新版libpulse不完全兼容。遇到这类问题优先考虑升级EKHO到新版本不要试图去改源码适配老API代价太大。另外飞腾、鲲鹏平台如果编译时默认开启某些CPU特定优化导致运行崩溃可以尝试在configure阶段禁用一些高级指令集比如./configure CFLAGS-O2 -pipe确保通用性优先。6.4 合成文件不完整或时长异常这个坑我最初没预料到。批量合成时个别文本生成的wav文件时长明显偏短甚至只有几百毫秒的空响。排查后发现问题出在文本中的特殊控制字符。比如从网页复制过来的文本里含有断行符、不可见Unicode字符如U200B零宽空格EKHO解析时把它们当作分段标记于是合成了极短的语音。解决办法是在预处理里用正则把非标准字符清掉import re text re.sub(r[\u200b\u200c\u200d\ufeff], , text) text re.sub(r\s, , text)这个经验的价值在于很多TTS“灵异问题”的根源不是引擎本身而是文本数据里的隐形垃圾字符。做语音合成项目文本清洗环节必须当成一等公民看待。7. 把“说”和“听”串起来搭配离线语音识别的小方案热搜词里同时出现了“语音转文本”我在本地环境也确实把这两块打通了这里顺手分享一下组合玩法。银河麒麟V10上做离线语音识别我推荐Vosk它和EKHO气质接近体积小、离线运行、CPU友好提供中文模型支持从麦克风实时识别或对音频文件批量识别。两者组合起来可以做一个不依赖云服务的“语音交互口袋方案”。我在一台飞腾D2000的麒麟V10上搭了一套语音便签系统逻辑很朴素系统通过arecord命令采集麦克风音频。达到指定静音阈值后停止录音把wav文件交给Vosk识别。识别文本写入当日便签文件。用户说“播放今天的便签”脚本就把文件内容经过EKHO合成为语音播放出来。核心脚本结构类似这样#!/bin/bash # 录音 arecord -f cd -t wav -d 5 /tmp/voice_note.wav # 语音识别vosk-transcriber 是Vosk的命令行工具 vosk-transcriber -i /tmp/voice_note.wav -o /tmp/voice_note.txt # 读文本并合成播放 cat /tmp/voice_note.txt | while IFS read -r line; do ekho $line done这个方案在不需要高精度的场景下完全够用。会议室记录、流水账备忘、口头指令下达识别准确率尚可关键是全程离线数据不出机器安全上让人放心。组合起来你会发现EKHO和Vosk放在一起形成了一个非常有意思的闭环一台不联网、配置不高的国产终端能听、能说、能写完全自主可控。很多轻量级自动化场景根本不需要等云端的某某大模型接口本机就搞定了。8. 提升可懂度和自然度的几个参数经验最后再聊一下怎么调出更“能听”的效果这部分属于个人经验未必对所有环境适用但思路是可以借鉴的。拼接合成的声音可懂度通常没问题但“自然度”确实需要花心思。我在长期使用后总结出三个调节方向第一语速宁慢勿快。很多人默认觉得播报语速快显得效率高实际上1.0以上语速对拼接语音来说是灾难相邻音节拼缝处理仓促听起来像赶鸭子。长期播报场景我固定在0.9~1.0之间。第二音调略微上调。前面提过-p 1.1这个值不是拍脑袋来的。我把同一段文本在0.9、1.0、1.1、1.2四档音调下各合成了一遍拿给同事盲听打分1.1的“清晰感”和“自然度”综合最好。1.2以上开始有电子味0.9以下闷得慌。建议你也用这个方法在自己的音箱上测一遍。第三文本分段要合理。长文本不要一次全塞给EKHO它会明显吃力。我写了个按标点切分的辅助函数逗号、句号、分号处断行再逐段合成最后用ffmpeg拼接ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.wav用-c copy直接复制数据流不做重编码速度快且无损。这个做法把长文本自然度提升了一大截也避免了单次合成字符串过长导致的内存问题。还有一点是关于输出格式的。EKHO默认输出的wav是单声道16bit PCM采样率通常是22050Hz或44100Hz具体取决于语音数据包配置。如需转换成mp3用于其他系统直接用ffmpegffmpeg -i output.wav -codec:a libmp3lame -qscale:a 6 output.mp3-qscale:a 6档位大约128kbps播报语音完全够用文件体积比原始wav小很多。回看这段从零开始折腾EKHO的经历我最大的体会是在国产化平台上做功能落地最稀缺的不是“新潮工具”而是“边界清晰、能离线跑、出了问题自己能修”的老实方案。EKHO的拼接式TTS虽然不像神经语音那么灵动但它所在的位置恰好补上了信创终端在语音输出上的空白而且把文本清洗、参数调优、流程封装这些基本功练扎实后效果完全能打。如果你也在麒麟系统上找语音方案不妨照着这条路径自己走一遍遇到问题欢迎对照排查。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。