当前位置: 首页 > news >正文

一文搞懂WeTextProcessing:让语音与文本处理项目告别数字乱码的归一化利器

一文搞懂WeTextProcessing:让语音与文本处理项目告别数字乱码的归一化利器

【免费下载链接】WeTextProcessingText Normalization & Inverse Text Normalization项目地址: https://gitcode.com/gh_mirrors/we/WeTextProcessing

一个让人头疼的场景

想象一下:你的语音识别系统刚上线,用户说了一句"下午三点二十分开会,花费二百九十九块九",结果系统输出的文字既不是标准数字,也不是规整的时间格式;反过来,TTS语音合成前,你丢给它一段"会议定于2023-12-25 14:30召开",它却把"2023-12-25"读得磕磕绊绊。数字、日期、货币、单位这些"非标准文本",在语音与文本系统之间来回转换时,总是容易翻车。

WeTextProcessing就是来解决这个问题的——一个专注文本归一化(Text Normalization,TN)与逆文本归一化(Inverse Text Normalization,ITN)的开源工具包,让你在不同格式之间一键切换,彻底告别乱码和误读。

它到底是什么,适合谁用

简单来说,WeTextProcessing做两件事:归一化是把"123"变成"一百二十三",逆归一化是把"一百二十三"变回"123"。它底层基于OpenFST和Pynini构建的有限状态转换器(FST)规则引擎,天然具备确定性高、处理速度快、规则可组合三大优点。

如果你在搞语音识别(ASR)后处理、语音合成(TTS)前处理、文本数据清洗,或者需要中英日多语言文本标准化,这个项目就是为你准备的。它最大的特点是"生产就绪"——不是实验室玩具,而是经历过真实业务打磨的成熟方案。

核心能力速览

能力说明
🌍 多语言覆盖内置中文、英文、日文三套独立规则引擎,互不干扰
🔄 双向转换TN(文本→可读语音文本)与 ITN(语音文本→标准格式)两条流水线
🧩 规则全覆盖数字、分数、百分比、日期、时间、货币、度量衡、数学符号、电话号码、儿化音、白名单替换等
⚡ FST 高性能规则编译成有限状态转换器,匹配速度接近 O(n)
🧠 智能缓存图缓存按内容寻址,规则或配置变化时自动重建,无需手工清理
📍 映射溯源支持获取输入输出之间精确的字符跨度映射,知道每一处改动来自哪条规则
🔧 双形态部署既提供 Python 接口,也提供 C++ 运行时,适合高性能场景

从零到跑通:10分钟上手

第一步:安装

最简单的途径是直接通过 pip 安装:

pip install WeTextProcessing

如果你打算自定义规则、修复 badcase,建议克隆源码仓库:

git clone https://gitcode.com/gh_mirrors/we/WeTextProcessing cd WeTextProcessing pip install -r requirements.txt

第二步:命令行快速体验

装好后,两个命令即可上手:

# 文本归一化:把数字转成中文读法 wetn --text "2.5平方电线" # 输出:二点五平方电线 # 逆文本归一化:把中文读法还原成数字 weitn --text "二点五平方电线" # 输出:2.5平方电线

第三步:Python 调用

在代码里使用同样简单,以中文为例:

from tn.chinese.normalizer import Normalizer from itn.chinese.inverse_normalizer import InverseNormalizer # 归一化:数字、符号 → 可朗读文本 zh_tn_model = Normalizer(remove_erhua=True) text = "2023年12月25日花费¥299.99购买了5kg苹果" print(zh_tn_model.normalize(text)) # 二零二三年十二月二十五日花费二百九十九点九九元购买了五千克苹果 # 逆归一化:朗读文本 → 标准书写格式 zh_itn_model = InverseNormalizer(enable_0_to_9=False) text = "下午三点二十分开会" print(zh_itn_model.normalize(text)) # 15:20开会

✅ 到这里,你已经能处理日常 90% 的转换需求了。

进阶玩法与技巧

技巧一:按需配置参数,让行为更贴合业务

中文归一化器提供了丰富的开关:

normalizer = Normalizer( remove_erhua=True, # 是否去除儿化音("这地儿"→"这地") traditional_to_simple=True, # 繁体转简体 remove_puncts=False, # 是否移除标点 full_to_half=True, # 全角转半角("IPHONE"→"IPHONE") tag_oov=False, # 是否标记未登录词 )

逆归一化器侧同样灵活,比如控制"个位数是否单独转换":

# 小于10的单独数字不转换:"幸运一百"保持中文,而不是变成"幸运100" inv = InverseNormalizer(enable_0_to_9=False) # 默认情况下,"一百"这类独立数字会转成100 inv2 = InverseNormalizer(enable_0_to_9=True)

这里有个小技巧:enable_standalone_number控制是否把句中独立出现的数字读法转成阿拉伯数字,exclue_one则决定"一年后"要不要变成"1年后"。业务上不确定时,先在测试数据上跑一遍再决定。

技巧二:用映射功能追查每一处改动

当你想知道"12"为什么被转成了"十二",以及改动发生在哪个位置时,用normalize_with_mapping

result = zh_tn_model.normalize_with_mapping("今天中午12点") print(result.output_text) # 今天中午十二点 for mapping in result.mappings: print(mapping.token_type, mapping.input_text, "=>", mapping.output_text) # math 12 => 十二

返回结果里不仅包含替换前后的文本,还带上了 Unicode 字符偏移量(半开区间),以及产出这次改动的规则类型。对排查 badcase 来说,这比"肉眼比对原文和结果"高效得多。注意:偏移量是 Python Unicode 字符偏移,不是 UTF-8 字节偏移。

技巧三:利用 n-best 输出兜底

两条 API 都支持联合 tagger/verbalizer 的 n-best 输出:

outputs = zh_tn_model.normalize("输入文本", nbest=3) # nbest=1 时返回字符串,nbest>1 时返回字符串列表

当主路径结果不满意时,可以从候选中挑选更合适的表达。

技巧四:缓存机制的正确打开方式

图编译是比较重的一次性操作,WeTextProcessing 内置了内容寻址缓存:

  • 缓存键包含全部图配置、Python 语法源码、TSV/FAR 资源与构建格式信息,规则一改,缓存自动失效重建,日常使用完全不用管
  • 只有想强制重建时才传overwrite_cache=True
  • 缓存默认写在系统用户缓存目录(如 Linux 下的~/.cache/wetextprocessing),不会污染源码树;
  • 也可以用cache_dir="/path/to/cache-root"指定缓存根目录,或传cache_dir=False完全走内存构建。

生产环境建议:预编译好规则图,关闭overwrite_cache,把编译结果分发到各服务节点复用。

技巧五:自定义规则修复 badcase

规则文件全部是 Python 源码,放在tn/chinese/rules/(归一化)和itn/chinese/rules/(逆归一化)目录下,数据词表则在对应语言的data/目录中(TSV 格式)。

改规则前,务必先读一遍 Python 规则架构文档。它的核心约定是:tagger 只负责分类并原样保留输入字段,真正的语义转换交给 verbalizer 完成。这条约定保证了输入输出跨度映射的精确性。

改完规则后,用--overwrite_cache强制重建图即可验证效果:

python -m tn --text "2.5平方电线" --overwrite_cache python -m itn --text "二点五平方电线" --overwrite_cache

命令行还支持--file PATH读取文件,或直接从标准输入读文本;每行输入会输出"标注结果 + 最终结果"两行。

技巧六:需要极致性能时上 C++ 运行时

runtime/目录下是一套完整的 C++ 实现,适合对延迟敏感的线上服务:

cmake -B build -DCMAKE_BUILD_TYPE=Release cmake --build build ./build/processor_main --tagger zh_tn_tagger.fst --verbalizer zh_tn_verbalizer.fst --text "2.5平方电线"

需要注意:Python 的缓存包是内部格式,不要直接把里面的路径传给processor_main;C++ 运行时需要的是单独导出的、配套的 tagger/verbalizer 文件对。

常见问题与避坑

Q1:全角半角、繁简、儿化音这些为什么"没生效"?这类字符级转换不在 tagger 里做,而是由 verbalizer/postprocessor 负责。这是有意设计——让 tagger 尽量保持输入原样,才能保证normalize_with_mapping()的映射真实可信。想改这类行为,看data/char/fullwidth_to_halfwidth.tsvdata/char/traditional_to_simple.tsvdata/erhua/whitelist.tsv这些词表即可。

Q2:为什么某些独立出现的数字没有被转换?多半是参数问题。中文 ITN 里enable_0_to_9enable_standalone_numberenable_million三个开关共同决定数字的转换范围;度量衡场景还有exclue_one控制"一"是否参与转换。按业务需求组合即可。

Q3:改了规则,但结果没变化?先确认是否真的重建了图。缓存键包含规则源码指纹,正常会自动失效,但如果你手动复制过缓存目录或修改了系统时间,可以显式传overwrite_cache=True强制重建。

Q4:映射结果和预期对不上?映射是沿着 tagger 和 verbalizer 的 WFST 路径追踪出来的,没有表层文本 diff 兜底。未被任何规则捕获的文本不会产生映射条目;想看到"保持原样"的 token,可以传include_identity=True

Q5:Windows 下缓存目录里出现残留文件?Windows 上中断构建的残留物不会自动清理(因为没有等价的无跟随目录操作),但它们是无害的,等没有进程占用缓存时手动删除即可。

Q6:安装依赖失败?核心依赖是pynini>=2.1.6importlib_resources,其中 pynini 需要本地 FST 工具链支持。装不上时优先确认编译环境是否完整。

总结与延伸

文本归一化看似是个小问题,却是语音产品体验的分水岭。WeTextProcessing 用 FST 规则引擎把这件事做得既快又稳:多语言覆盖、双向转换、精确映射、智能缓存,再加上 Python/C++ 双形态,从开发调试到生产部署一路畅通。

想继续深入,可以按这个路径走:

  • 快速阅读tn/README.mditn/README.md,里面有完整的 TN/ITN 流水线说明和大量输入输出对照表;
  • 想动手改规则的,重点研读 docs/python-rule-architecture.md,并参考各语言rules/目录下的既有实现;
  • 想贡献新语言的,可以对照tn/japanese/这类已有模板,把数据词表和规则类补齐即可;
  • 关注底层原理的,可以研究 OpenFST 与 Pynini 的图组合、权重分配(add_weight)与最短路径搜索,这些知识在排查复杂 badcase 时会非常有用。

项目本身还在持续演进,规则词表、语言覆盖和运行时能力都在不断更新。无论你是要做 ASR 后处理、TTS 前处理还是通用文本标准化,都可以先从wetn --text "2.5平方电线"这行命令开始,体验一把"文本瞬间变得会说话"的感觉。🚀

【免费下载链接】WeTextProcessingText Normalization & Inverse Text Normalization项目地址: https://gitcode.com/gh_mirrors/we/WeTextProcessing

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.cnnetsun.cn/news/4070552.html

相关文章:

  • Bitwarden:开源免费的跨平台密码管理器,端到端加密
  • 热门八股-JUC
  • 特斯拉Model 3如何以鲶鱼效应重塑中国新能源汽车产业格局
  • 江西五十铃新款D-MAX谍照解析:中期改款设计、动力与市场前瞻
  • 网盘直链下载怎么玩才不折腾?我的两年亲测与避坑记录
  • 微信读书网页版字体自定义:CSS注入与Tampermonkey脚本实战
  • Linux Shell特殊符号完全指南:从重定向到管道,掌握命令行核心语法
  • 请求绑定与校验
  • 被苹果放弃的老电脑,我用一个免费工具让它重获新生
  • sva日常学习0
  • RuoYi-Vue Pro 完整上手指南:1 小时搭建带权限与审批的企业级后台
  • AI水印技术解析:从SynthID到C2PA标准,开发者如何管理水印可见性
  • 5分钟跑起跨平台QSP播放器:JavaQuestPlayer完整上手与实测体验
  • PCSX2免费开源模拟器完整指南:如何在家用电脑上高清重玩PS2经典游戏
  • 166、Zephyr RTOS调试与测试基础:调试工具链
  • 虚拟机中OpenFOAM-v2012与Paraview完整安装配置指南
  • Cursor免费使用受阻?一份解决设备限制与机器ID重置的完整指南
  • IoT OTA差分升级:bspatch减小固件体积
  • 如何让《暗黑破坏神2》在现代电脑上满帧运行?D2DX宽屏补丁完整上手指南
  • 每天省下一小时重复劳动的炉石传说插件:HsMod到底能帮你做什么
  • 从一脸懵到轻松绕过:Awesome-WAF 帮你 3 步吃透 Web 应用防火墙攻防测试
  • Ryujinx模拟器终极调优攻略:从装不上到丝滑畅玩的完整实操
  • 系统架构设计师考试模拟题库(下):案例分析与论文指导
  • League Akari 英雄联盟客户端工具箱终极指南:自动选人、流程自动化与对局洞察一网打尽
  • Qwen3.8-27B多模态大模型实战:从技术验货到工程化部署全指南
  • Outfit字体实操指南:免费可商用的几何无衬线字体如何一站式打通品牌视觉统一?
  • 汽车测试谍照背后的产品生命周期管理逻辑与市场策略
  • 构建游戏指令智能系统:从数据建模到安全执行的工程实践
  • YOLO 涨点改进|全网独家复现单通道红外小目标增强 光伏板鸟粪微弱热斑识别、分布式光伏无人机巡检全场景有效涨点
  • 5分钟上手DeepL翻译插件:用开源Chrome划词翻译扩展告别来回切换