FST ITN-ZH教程:如何扩展支持更多中文文本类型
1. 简介与背景
中文逆文本标准化(Inverse Text Normalization, ITN)是语音识别系统中不可或缺的一环。其核心任务是将模型输出的口语化、非结构化中文表达,转换为标准、可计算的格式。例如:
二零零八年八月八日→2008年08月08日早上八点半→8:30a.m.一百二十三→123
FST ITN-ZH 是一个基于有限状态转导器(Finite State Transducer, FST)实现的中文ITN工具,具备高精度、低延迟的特点。当前版本已支持日期、时间、数字、货币等常见类型,但实际业务场景中常需处理更复杂的表达形式。
本文将详细介绍如何对FST ITN-ZH 的 WebUI 进行二次开发,并扩展其功能以支持更多中文文本类型,如电话号码、身份证号、地址缩写等,提升系统的实用性与覆盖范围。
2. 系统架构与工作原理
2.1 整体架构概览
FST ITN-ZH 的处理流程如下:
输入文本 ↓ 分词与模式匹配(正则/规则) ↓ FST 转换引擎(基于 OpenFST 或 pynini) ↓ 标准化输出 ↓ WebUI 展示结果其中:
- 前端:Gradio 构建的 WebUI,提供交互界面
- 后端:Python + pynini 实现的 FST 规则引擎
- 数据流:用户输入 → 规则匹配 → FST 转换 → 返回结果
2.2 FST 核心机制解析
FST 是一种双态自动机,能够定义输入符号串到输出符号串的映射关系。在 ITN 中,每个转换类型(如“数字”)都对应一组 FST 规则。
以“中文数字转阿拉伯数字”为例,关键规则包括:
import pynini # 定义基本数字映射 digit_map = pynini.string_map([ ("零", "0"), ("一", "1"), ("二", "2"), ("三", "3"), ("四", "4"), ("五", "5"), ("六", "6"), ("七", "7"), ("八", "8"), ("九", "9") ]) # 构建万进制单位转换逻辑 def build_number_fst(): # 千、百、十等单位处理 ... return fst这些规则最终被编译成加权有限状态机,在线性时间内完成转换。
3. 扩展新文本类型的实现步骤
3.1 新增“电话号码”支持
需求分析
中文语音中常见的电话号码表达方式:
幺七八六五四三二幺零一七七 六六六六 七七七七
目标输出:
178654321017766667777
实现方案
- 定义正则匹配模式
import re def detect_phone(text): pattern = r'(?:[一二三四五六七八九零壹贰叁肆伍陆柒捌玖零]十)?' \ r'[幺一二三四五六七八九][零一二三四五六七八九]{10}' matches = re.findall(pattern, text) return matches- 构建 FST 映射规则
phone_digit_map = pynini.string_map([ ("零", "0"), ("一", "1"), ("二", "2"), ("三", "3"), ("四", "4"), ("五", "5"), ("六", "6"), ("七", "7"), ("八", "8"), ("九", "9"), ("幺", "1") ]) # 编译为替换规则 phone_fst = pynini.transducer("", "", input_token_type="utf8", output_token_type="utf8") for inp, out in phone_digit_map.pairs(): phone_fst |= pynini.cross(inp, out)- 集成至主流程
from fst_itn.core import compose_fsts # 将电话号码规则加入总规则链 final_fst = ( date_fst @ time_fst @ number_fst @ currency_fst @ phone_fst # 新增 )- WebUI 添加开关控制
在app.py中添加复选框:
with gr.Accordion("高级设置"): convert_phone = gr.Checkbox(label="转换电话号码", value=True)并在推理时判断是否启用:
if convert_phone: text = apply_fst(text, phone_fst)3.2 支持“身份证号”标准化
特点分析
- 长度固定:18位(末位可能为X)
- 包含出生日期段:前6位为地区码,7-14位为出生年月日
- 常见读法:
一九九零年一月一日对应19900101
实现策略
拆解结构
- 地区码:忽略,保持原样
- 出生日期:调用已有日期ITN模块
- 顺序码+校验码:直接转数字
组合式处理
def normalize_id_card(text): # 提取出生日期部分并标准化 birth_part = extract_date_span(text) # 如“一九九零年一月一日” normalized_birth = itn_date(birth_part) # → 19900101 # 拼接其余部分 rest_digits = text.replace(birth_part, "") cleaned_rest = "".join([cn_to_digit(c) for c in rest_digits]) return f"{normalized_birth}{cleaned_rest}"- 边界处理
- 支持“X”读作“叉”或“西”
- 处理连读情况,如“一二三四五”→“12345”
3.3 增加“地址缩写”识别能力
典型场景
北京市朝阳区→北京朝阳广东省深圳市南山区→广东深圳南山
解决思路
使用预定义行政区划表进行匹配:
PROVINCES = ["北京", "上海", "广东", "江苏", ...] CITIES = {"北京": ["朝阳", "海淀"], "深圳": ["南山", "福田"], ...} def shorten_address(text): for province in PROVINCES: if province in text: for city in CITIES.get(province, []): if city in text: return f"{province}{city}" return text # 未匹配则保留原样该函数可在 FST 流程之后作为后处理步骤调用。
4. 工程优化与最佳实践
4.1 性能优化建议
缓存编译后的 FST
@lru_cache(maxsize=1) def get_compiled_fst(): return compile_rules()批量处理减少开销
- 批量转换时统一加载模型,避免重复初始化
- 使用
pynini.compose批量执行多个转换
异步响应提升体验
async def async_convert(text): loop = asyncio.get_event_loop() result = await loop.run_in_executor(None, sync_itn, text) return result
4.2 错误处理与鲁棒性增强
- 添加输入合法性校验
- 设置超时机制防止长文本阻塞
- 记录异常日志便于调试
try: result = apply_itn_rules(input_text) except Exception as e: logging.error(f"ITN failed on '{input_text}': {str(e)}") return input_text # 失败时返回原文4.3 可配置化设计
通过 JSON 配置文件管理各类开关:
{ "enable_phone": true, "enable_id_card": false, "convert_single_digit": true, "fully_expand_wan": false }启动时加载配置,实现灵活部署。
5. 总结
5. 总结
本文围绕FST ITN-ZH 中文逆文本标准化系统的功能扩展进行了深入探讨,重点讲解了如何通过二次开发支持更多中文文本类型。主要内容包括:
- 理解系统架构:掌握基于 FST 的 ITN 工作机制,明确前后端协作流程。
- 新增电话号码支持:利用正则匹配与 FST 映射,实现“幺七八”到“178”的精准转换。
- 身份证号标准化:结合日期ITN模块,完成复合结构的分段处理。
- 地址缩写优化:引入行政区划知识库,提升语义简洁性。
- 工程化改进:提出性能优化、错误处理和配置化等可落地的最佳实践。
通过上述方法,开发者可以持续扩展 FST ITN-ZH 的能力边界,适应更多真实应用场景。未来还可进一步探索:
- 结合 NLP 模型做上下文感知转换
- 支持方言变体(如粤语数字)
- 提供 API 接口供外部系统调用
本项目由科哥进行 WebUI 二次开发,承诺永久开源使用,请保留版权信息。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。