Skip to content

Repository files navigation

FST Time NLU

时间表达式识别与解析

CI License Python Code style: black


🚀 在线演示

👉 立即体验在线演示 👈

无需安装,在浏览器中直接体验时间表达式识别!


简介

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
  • 节假日:春节国庆节ChristmasThanksgiving
  • 农历:正月初一腊月二十三
  • 重复时间:每天上午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。

如何使用

1. 快速开始

1.1 安装

# 从源码安装
git clone https://github.com/y00281951/fst-time-nlu.git
cd fst-time-nlu
pip install -r requirements.txt

1.2 命令行使用

# 中文时间解析
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 chinese

1.3 Python API 使用

from 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']

2. 高级用法

2.1 自定义规则

如果需要修改或添加规则来修复 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

2.2 使用自定义规则

成功重建规则后,你可以在已安装的包中使用它们:

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)                         │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐      │
│  │ 词典数据  │ │ 节假日   │ │ 数字映射  │ │ 配置文件  │      │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘      │
└─────────────────────────────────────────────────────────────┘

核心模块说明

1. FstTimeExtractor(时间提取器)

  • 职责:统一的时间提取接口
  • 功能
    • 整合文本标准化和时间解析
    • FST 模型缓存管理
    • 性能统计和监控
  • 使用:用户直接调用的主入口

2. Normalizer(文本标准化器)

  • 职责:将自然语言文本转换为结构化标签
  • 功能
    • FST 模型加载和编译
    • 文本预处理(繁简转换、全半角转换等)
    • 模式匹配和标签生成
  • 输入:原始文本(如"明天上午9点")
  • 输出:结构化标签(如"TIME#2025-01-22T09:00:00Z")

3. TimeParser(时间解析器)

  • 职责:将标签转换为具体的时间值
  • 功能
    • 标签解析和验证
    • 相对时间转绝对时间
    • 上下文合并和冲突解决
  • 输入:标签序列
  • 输出:ISO 8601 格式时间字符串

4. Parsers(专用解析器)

  • RelativeParser:处理相对时间(明天、下周、3天后)
  • BetweenParser:处理时间区间(从...到...)
  • HolidayParser:处理节假日(春节、圣诞节)
  • LunarParser:处理农历(正月初一、腊月二十三)
  • PeriodParser:处理时间段(上午、下午、晚上)
  • WeekParser:处理星期(周一、周末)
  • DeltaParser:处理时间差(3小时后、2天前)
  • RecurringParser:处理重复时间(每天、每周一)

5. Rules(FST 规则)

  • 职责:定义时间表达式的识别规则
  • 技术:基于 pynini 库构建 FST
  • 特点
    • 声明式规则定义
    • 可组合、可复用
    • 支持权重和优先级

6. Data(数据资源)

  • 词典数据:时间词汇、数字映射
  • 节假日数据:中国节假日、国际节假日
  • 配置文件:解析器配置、规则参数

主要功能特性

核心功能

  • 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

支持的时间表达式类型

绝对时间与相对时间(UTCTimeRule / RelativeRule)

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"] 从句子中识别相对月份日期

时间增量与星期(DeltaRule / WeekRule)

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"] 识别某个月的第几个星期

时段、节假日与农历(时段规则 / HolidayRule / LunarRule)

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"] 从句子中识别农历日期

时间范围、时期与区间(RangeRule / PeriodRule / BetweenRule)

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

支持的时间表达式类型

绝对时间与相对时间(UTCTimeRule / RelativeRule)

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"]] 识别序数日期格式

时间增量与星期(TimeDeltaRule / WeekRule)

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"]] 识别复合星期表达

时段、节假日(PeriodRule / HolidayRule)

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"]] 识别跨天的时间段

时间范围、时期与区间(RangeRule / TimeRangeRule / CenturyRule)

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

核心模块说明

FstTimeExtractor (主入口)

  • 提供统一的时间提取接口
  • 整合文本标准化和时间解析功能
  • 支持FST模型缓存管理

文本处理流程

  1. 预处理 (preprocessor.py): 文本清洗和标准化
  2. FST识别 (test/fst/zh_tn_tagger.fst): 使用FST模型识别时间实体
  3. 规则解析 (rules/): 应用语法规则进行精确解析
  4. 后处理 (postprocessor.py): 结果标准化和验证

架构特点

  1. 模块化设计: 核心处理逻辑与语言特定实现分离
  2. 可扩展性: 支持添加新的解析器和规则
  3. 高性能: FST模型提供高效的模式匹配
  4. 鲁棒性: 多层次的错误处理和容错机制

依赖项

核心依赖

  • 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 - 代码检查

讨论与交流

欢迎通过以下方式参与讨论:

致谢

  1. 感谢 OpenFstPynini 等基础库的作者
  2. 感谢 WeTextProcessing 项目提供的参考和启发
  3. 感谢所有为本项目做出贡献的开发者

许可证

本项目采用 Apache License 2.0 许可证。

Copyright (c) 2025 OPPO

OPPO AI Center, LLM Algorithm Department

Citation

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}}
}

About

Extracting time features from text using a Finite State Transducer (FST) in Python

Resources

Contributing

Stars

68 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages