👉 立即体验在线演示 👈
无需安装,在浏览器中直接体验时间表达式识别!
FST Time NLU 是一个生产级的时间表达式识别与解析工具包,基于有限状态转换器(Finite-State Transducer)技术。
核心特性:
- ⚡ 高性能:平均推理时延 ~4ms,比深度学习方法快 10-100 倍
- 🎯 高准确率:95%+ 准确率,支持多种复杂时间表达
- 🌏 双语支持:中文和英文时间表达式
- 🔧 易于定制:基于规则,可快速修改和扩展
- 📦 开箱即用:提供 Python API 和命令行工具,可直接作为submodule使用
支持的时间表达式类型:
- 绝对时间:
2025年1月21日上午9点、January 21, 2025 at 9 AM - 相对时间:
明天上午9点、下周一、3天后、tomorrow at 9 AM - 时间区间:
从明天到后天、上午9点到下午5点、from 9 AM to 5 PM - 节假日:
春节、国庆节、Christmas、Thanksgiving - 农历:
正月初一、腊月二十三 - 重复时间:
每天上午9点、每周一、every Monday
# 克隆仓库
git clone https://github.com/y00281951/fst-time-nlu.git
cd fst-time-nlu
# 安装依赖
pip install -r requirements.txt
# 启动 Web 应用
streamlit run app.py然后在浏览器中打开 http://localhost:8501 即可使用!
部署指南:查看 .streamlit/DEPLOYMENT_GUIDE.md 了解如何将应用部署到 Streamlit Cloud。
# 从源码安装
git clone https://github.com/y00281951/fst-time-nlu.git
cd fst-time-nlu
pip install -r requirements.txt# 中文时间解析
python main.py --text "明天上午9点" --language chinese
# 英文时间解析
python main.py --text "tomorrow at 9 AM" --language english
# 批量处理文件
python main.py --file src/chinese/test/groundtruth_utc.jsonl --language chinesefrom src.chinese.fst_time_extractor import FstTimeExtractor
# 创建提取器实例
extractor = FstTimeExtractor(overwrite_cache=False)
# 解析时间文本
datetime_results, query_tag = extractor.extract(
"明天上午9点开会",
base_time="2025-01-21T08:00:00Z"
)
print(f"识别结果: {datetime_results}")
# 输出: 识别结果: ['2025-01-22T09:00:00Z']
# 处理时间区间
datetime_results, query_tag = extractor.extract(
"从明天上午9点到下午5点",
base_time="2025-01-21T08:00:00Z"
)
print(f"识别结果: {datetime_results}")
# 输出: 识别结果: ['2025-01-22T09:00:00Z', '2025-01-22T17:00:00Z']如果需要修改或添加规则来修复 badcase,请尝试:
git clone https://github.com/y00281951/fst-time-nlu.git
cd fst-time-nlu
pip install -r requirements.txt
# `overwrite_cache` 会根据你对 src/chinese/rules/xx.py 的修改重新构建所有规则
# 重新构建后,你可以在当前目录找到新的 .fst 文件
python main.py --text "明天上午9点" --language chinese --overwrite_cache成功重建规则后,你可以在已安装的包中使用它们:
from src.chinese.fst_time_extractor import FstTimeExtractor
# 使用自定义缓存目录
extractor = FstTimeExtractor(cache_dir="PATH_TO_YOUR_CUSTOM_CACHE")
datetime_results, query_tag = extractor.extract("明天上午9点")
print(datetime_results)┌─────────────────────────────────────────────────────────────┐
│ 用户接口层 │
│ ┌──────────────────────────┐ ┌──────────────────────┐ │
│ │ Python API │ │ 命令行工具 │ │
│ └──────────────────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 时间提取器层 (FstTimeExtractor) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ • 统一接口封装 │ │
│ │ • 缓存管理 │ │
│ │ • 性能统计 │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 文本标准化层 (Normalizer) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ • FST 模型加载与编译 │ │
│ │ │ 文本预处理 → FST 识别 → 标签生成 │ │
│ │ • 繁简转换、全半角转换、数字归一化 │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 时间解析层 (TimeParser) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ • 标签解析与时间计算 │ │
│ │ • 相对时间转绝对时间 │ │
│ │ • 上下文合并与冲突解决 │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 解析器层 (Parsers) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 相对时间 │ │ 时间区间 │ │ 节假日 │ │ 农历 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 时间差 │ │ 时间段 │ │ 星期 │ │ UTC时间 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 规则层 (Rules) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ • FST 规则定义(基于 pynini) │ │
│ │ • 语言学规则编码 │ │
│ │ • 模式匹配与转换 │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 数据资源层 (Data) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 词典数据 │ │ 节假日 │ │ 数字映射 │ │ 配置文件 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
- 职责:统一的时间提取接口
- 功能:
- 整合文本标准化和时间解析
- FST 模型缓存管理
- 性能统计和监控
- 使用:用户直接调用的主入口
- 职责:将自然语言文本转换为结构化标签
- 功能:
- FST 模型加载和编译
- 文本预处理(繁简转换、全半角转换等)
- 模式匹配和标签生成
- 输入:原始文本(如"明天上午9点")
- 输出:结构化标签(如"TIME#2025-01-22T09:00:00Z")
- 职责:将标签转换为具体的时间值
- 功能:
- 标签解析和验证
- 相对时间转绝对时间
- 上下文合并和冲突解决
- 输入:标签序列
- 输出:ISO 8601 格式时间字符串
- RelativeParser:处理相对时间(明天、下周、3天后)
- BetweenParser:处理时间区间(从...到...)
- HolidayParser:处理节假日(春节、圣诞节)
- LunarParser:处理农历(正月初一、腊月二十三)
- PeriodParser:处理时间段(上午、下午、晚上)
- WeekParser:处理星期(周一、周末)
- DeltaParser:处理时间差(3小时后、2天前)
- RecurringParser:处理重复时间(每天、每周一)
- 职责:定义时间表达式的识别规则
- 技术:基于 pynini 库构建 FST
- 特点:
- 声明式规则定义
- 可组合、可复用
- 支持权重和优先级
- 词典数据:时间词汇、数字映射
- 节假日数据:中国节假日、国际节假日
- 配置文件:解析器配置、规则参数
- FST模型: 基于有限状态转换器的高效时间表达式识别
- 多格式支持: 支持绝对时间、相对时间、时间区间等多种表达方式
- 文本标准化: 自动处理繁简转换、全半角转换、数字归一化等
- 缓存机制: FST模型缓存,提升重复使用性能
- 基础解析器 (
base_parser.py): 提供解析器基础功能 - 时间区间解析器 (
between_parser.py): 处理"从...到..."类型的时间区间 - 时间差解析器 (
delta_parser.py): 处理相对时间差,如"3小时后" - 节假日解析器 (
holiday_parser.py): 识别中国传统节假日 - 农历解析器 (
lunar_parser.py): 支持农历时间表达式 - 时间段解析器 (
period_parser.py): 处理"上午"、"晚上"等时间段 - 相对时间解析器 (
relative_parser.py): 处理"明天"、"下周"等相对表达 - UTC时间解析器 (
utctime_parser.py): 处理UTC时间格式 - 星期解析器 (
week_parser.py): 处理星期相关表达式 - 上下文合并器 (
context_merger.py): 智能合并多个时间token,处理复杂时间表达式的组合,如"明天上午9点"、"下周一晚上8点"等
basetime默认为2025-01-21T08:00:00
| Query | Result | 备注 |
|---|---|---|
| 查询20240307计划 | ["2024-03-07T00:00:00Z", "2024-03-07T23:59:59Z"] |
从句子中识别纯数字日期 |
| 农历二〇二〇年十二月二十九日原告去被告家看嫁妆 | ["2021-02-10T00:00:00Z", "2021-02-10T23:59:59Z"] |
从长句中识别中文数字日期 |
| 住在南京网2021-09-21热度 578瞰地 | ["2021-09-21T00:00:00Z", "2021-09-21T23:59:59Z"] |
从句子中识别日期 |
| 下下下周一 | ["2025-02-10T00:00:00Z", "2025-02-10T23:59:59Z"] |
识别多重相对时间 |
| 上上个月五号 | ["2024-11-05T00:00:00Z", "2024-11-05T23:59:59Z"] |
识别多重相对月份加日期 |
| 他在10月22出生 | ["2025-10-22T00:00:00Z", "2025-10-22T23:59:59Z"] |
从句子中识别相对月份日期 |
| Query | Result | 备注 |
|---|---|---|
| 大概六天后的3时1刻需要处理东西 | ["2025-01-27T03:15:00Z"] |
模糊时间增量加精确时刻 |
| 在近一年的时间内保 | ["2024-01-06T00:00:00Z", "2025-01-06T00:00:00Z"] |
从句子中识别时间范围 |
| 周一或周二都可以 | [['2025-01-20T00:00:00Z', '2025-01-20T23:59:59Z'], ['2025-01-21T00:00:00Z', '2025-01-21T23:59:59Z']] |
识别多个星期选项 |
| 6月第3个星期日 | ["2025-06-15T00:00:00Z", "2025-06-15T23:59:59Z"] |
识别某个月的第几个星期 |
| Query | Result | 备注 |
|---|---|---|
| 大前天晚上9~11点 | ["2025-01-03T21:00:00Z", "2025-01-03T23:00:00Z"] |
多重相对时间加时段范围 |
| 今晚八点30到明天上午 | ["2025-01-21T20:30:00Z", "2025-01-22T12:00:00Z"] |
识别跨天的时间段 |
| 3月11日下午15:30-17:00 | ["2025-03-11T15:30:00Z", "2025-03-11T17:00:00Z"] |
日期加时段范围 |
| 明年母亲节 | ["2026-05-10T00:00:00Z", "2026-05-10T23:59:59Z"] |
识别相对年份加节日 |
| 冬至那天 | ["2025-12-21T00:00:00Z", "2025-12-21T23:59:59Z"] |
识别节气日期 |
| 农历二〇二〇年十二月二十九日原告去被告家看嫁妆 | ["2021-02-10T00:00:00Z", "2021-02-10T23:59:59Z"] |
从长句中识别完整农历日期 |
| 今年腊月18000吨物品被寄 | ["2024-12-31T00:00:00Z", "2025-01-28T23:59:59Z"] |
从长句子中找出农历时间 |
| 腊月18,已经过了好几天 | ["2025-01-17T00:00:00Z", "2025-01-17T23:59:59Z"] |
从句子中识别农历日期 |
| Query | Result | 备注 |
|---|---|---|
| 帮我查下15点20分到16点30的会议室 | ["2025-01-21T15:20:00Z", "2025-01-21T16:30:00Z"] |
从句子中识别时刻范围 |
| 1月3至2月10 | ["2025-01-03T00:00:00Z", "2025-02-10T23:59:59Z"] |
识别月份日期范围 |
| 在2021年4月20日11:00至2021年4月25日17:00对对方为 | [["2021-04-20T11:00:00Z", "2021-04-25T17:00:00Z"]] |
从长句子中找出时间范围 |
| 2018年年底 | ["2018-11-01T00:00:00Z", "2018-12-31T23:59:59Z"] |
识别指定年份的年底 |
| 过去一个月所有生产事故问题统计 | ["2024-12-06T00:00:00Z", "2025-01-06T00:00:00Z"] |
从句子中识别时期范围 |
| 上个世纪 | ["1900-01-01T00:00:00Z", "1999-12-31T23:59:59Z"] |
识别世纪时间范围 |
| 20世纪60年代前期 | ["1960-01-01T00:00:00Z", "1969-12-31T23:59:59Z"] |
识别年代前期时间范围 |
| Query | Result | 备注 |
|---|---|---|
| 再说两点 | [] |
"两点"表示列举要点,不识别为时间 |
| 简洁一点 | [] |
"一点"表示程度,不识别为时间 |
| 是一个十一点的事 | [["2025-07-25T11:00:00Z"]] |
"十一点"在时间语境中正确识别 |
| Query | Result | 备注 |
|---|---|---|
| 45901 | [] |
纯数字不是日期,不识别 |
| 身份证号140302197706220124 | [] |
身份证号中的数字不识别为日期 |
| 黎明主演的电影已上映 | [] |
"黎明"是人名,不识别为时间 |
| 一日之计在于晨 | [] |
成语中的时间词不识别 |
basetime默认为2025-01-21T08:00:00Z
| Query | Result | 备注 |
|---|---|---|
| living in nanjing net 2021-09-21 popularity 578 view | [["2021-09-21T00:00:00Z", "2021-09-21T23:59:59Z"]] |
从长句中识别日期 |
| three Mondays from now | [["2025-02-10T00:00:00Z", "2025-02-10T23:59:59Z"]] |
识别多重星期增量 |
| the day after tomorrow | [["2025-01-23T00:00:00Z", "2025-01-23T23:59:59Z"]] |
识别复合相对时间 |
| day after tomorrow 5pm | [["2025-01-23T17:00:00Z"]] |
相对日期加精确时刻 |
| march 3 2015 | [["2015-03-03T00:00:00Z", "2015-03-03T23:59:59Z"]] |
识别完整日期格式 |
| the first of march | [["2025-03-01T00:00:00Z", "2025-03-01T23:59:59Z"]] |
识别序数日期格式 |
| Query | Result | 备注 |
|---|---|---|
| in a couple of minutes | [["2025-01-21T08:02:00Z"]] |
识别模糊时间增量 |
| in a few hours | [["2025-01-21T11:00:00Z"]] |
识别模糊小时增量 |
| first tuesday of october | [["2025-10-07T00:00:00Z", "2025-10-07T23:59:59Z"]] |
识别某个月的第几个星期 |
| last Monday of March | [["2025-03-31T00:00:00Z", "2025-03-31T23:59:59Z"]] |
识别某个月的最后几个星期 |
| third tuesday of september 2014 | [["2014-09-16T00:00:00Z", "2014-09-16T23:59:59Z"]] |
识别指定年份某个月的第几个星期 |
| wednesday after next | [["2025-01-29T00:00:00Z", "2025-01-29T23:59:59Z"]] |
识别复合星期表达 |
| Query | Result | 备注 |
|---|---|---|
| late last night | [["2025-01-20T18:00:00Z", "2025-01-20T23:59:59Z"]] |
识别多重相对时间加时段 |
| tonight at 8 o'clock | [["2025-01-21T20:00:00Z"]] |
识别相对时段加精确时刻 |
| morning of christmas 2013 | [["2025-12-25T06:00:00Z", "2025-12-25T12:00:00Z"]] |
识别节日加时段 |
| next thanksgiving day | [["2026-11-26T00:00:00Z", "2026-11-26T23:59:59Z"]] |
识别相对年份加节日 |
| next Martin Luther King day | [["2026-01-19T00:00:00Z", "2026-01-19T23:59:59Z"]] |
识别复杂节日名称 |
| from tonight 8:30 to tomorrow morning | [["2025-01-21T20:30:00Z", "2025-01-22T12:00:00Z"]] |
识别跨天的时间段 |
| Query | Result | 备注 |
|---|---|---|
| from 9:30 - 11:00 on Thursday | [["2025-01-23T09:30:00Z", "2025-01-23T11:00:00Z"]] |
从句子中识别时刻范围加星期 |
| between 9:30 and 11:00 on thursday | [["2025-01-23T09:30:00Z", "2025-01-23T11:00:00Z"]] |
识别between表达的时刻范围 |
| scheduled from april 20 2021 11:00 to april 25 2021 17:00 | [["2021-04-20T11:00:00Z", "2021-04-25T17:00:00Z"]] |
从长句子中找出完整时间范围 |
| for 10 days from 18th Dec | [["2025-12-18T00:00:00Z", "2025-12-28T23:59:59Z"]] |
识别持续天数范围 |
| last 2 years | [["2023-01-21T08:00:00Z", "2025-01-21T08:00:00Z"]] |
识别多年时间范围 |
| last century | [["1900-01-01T00:00:00Z", "1999-12-31T23:59:59Z"]] |
识别世纪时间范围 |
| the 80s | [["1980-01-01T00:00:00Z", "1989-12-31T23:59:59Z"]] |
识别年代时间范围 |
| Query | Result | 备注 |
|---|---|---|
| 2015-03-28 17:00:00/2015-03-29 21:00:00 | [["2015-03-28T17:00:00Z"], ["2015-03-29T21:00:00Z"]] |
识别多个时间点 |
| today that huizhou solar calendar march 8th | [["2025-01-21T00:00:00Z", "2025-01-21T23:59:59Z"], ["2025-03-08T00:00:00Z", "2025-03-08T23:59:59Z"]] |
从复杂句子中识别多个时间 |
| what do i need to prepare in advance if i want to go to chiang mai next new year's day | [["2026-01-01T00:00:00Z", "2026-01-01T23:59:59Z"]] |
从长句子中识别相对节日 |
| Query | Result | 备注 |
|---|---|---|
| ten-thirty | [] |
"ten-thirty"表示数量,不识别为时间 |
| laughing out loud | [] |
"lol"缩写不识别为时间 |
| this is the one | [] |
"one"表示指代,不识别为时间 |
| Query | Result | 备注 |
|---|---|---|
| 1974 | [] |
纯数字不是日期,不识别 |
| 1 adult | [] |
"1 adult"表示数量,不识别为时间 |
| 25 | [] |
单独数字不是日期,不识别 |
| 指标 | 数值 |
|---|---|
| 平均推理时延 | ~4ms |
| CPU 占用 | 低 |
| 内存占用 | < 100MB |
| 并发支持 | 是 |
| 语言 | 测试集规模 | 准确率 |
|---|---|---|
| 中文 | 300+ 样本 | 95%+ |
| 英文 | 700+ 样本 | 95%+ |
# 中文基准测试
python main.py --language chinese --file src/chinese/test/groundtruth_utc.jsonl
# 英文基准测试
python main.py --language english --file src/english/test/groundtruth_utc_700english.jsonl- 提供统一的时间提取接口
- 整合文本标准化和时间解析功能
- 支持FST模型缓存管理
- 预处理 (
preprocessor.py): 文本清洗和标准化 - FST识别 (
test/fst/zh_tn_tagger.fst): 使用FST模型识别时间实体 - 规则解析 (
rules/): 应用语法规则进行精确解析 - 后处理 (
postprocessor.py): 结果标准化和验证
- 模块化设计: 核心处理逻辑与语言特定实现分离
- 可扩展性: 支持添加新的解析器和规则
- 高性能: FST模型提供高效的模式匹配
- 鲁棒性: 多层次的错误处理和容错机制
pynini>=2.1.5- FST 构建和处理python-dateutil>=2.8.0- 日期时间工具zhdate- 中文日期处理lunarcalendar- 农历支持inflect>=5.0.0- 英文数字处理
pytest>=6.0.0- 测试框架black>=21.0.0- 代码格式化flake8>=3.8.0- 代码检查
欢迎通过以下方式参与讨论:
- GitHub Issues - 报告问题、提出建议
- GitHub Discussions - 技术讨论、使用交流
- 感谢 OpenFst 和 Pynini 等基础库的作者
- 感谢 WeTextProcessing 项目提供的参考和启发
- 感谢所有为本项目做出贡献的开发者
本项目采用 Apache License 2.0 许可证。
Copyright (c) 2025 OPPO
OPPO AI Center, LLM Algorithm Department
If this project helps your research or work, feel free to cite:
@misc{fst-time-nlu,
title={FST Time NLU: Production First Time Expression Recognition},
author={Ming Yu, Liangliang Han, Ri Zhang, Shuo Yuan, Cong Wang},
year={2025},
publisher={GitHub},
howpublished={\url{https://https://github.com/OPPO-Mente-Lab/fst-time-nlu}}
}