Metadata-Version: 2.4
Name: textsentinel
Version: 0.1.0
Summary: 面向训练语料的工业级文本质量分类器（61 维特征 + LightGBM）
Author-email: axliupore <axliupore@gmail.com>
License:                                  Apache License
                                   Version 2.0, January 2004
                                http://www.apache.org/licenses/
        
           Copyright 2026 axliupore
        
           Licensed under the Apache License, Version 2.0 (the "License");
           you may not use this file except in compliance with the License.
           You may obtain a copy of the License at
        
               http://www.apache.org/licenses/LICENSE-2.0
        
           Unless required by applicable law or agreed to in writing, software
           distributed under the License is distributed on an "AS IS" BASIS,
           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           See the License for the specific language governing permissions and
           limitations under the License.
        
Project-URL: Homepage, https://github.com/axliupore/textsentinel
Project-URL: Documentation, https://textsentinel.readthedocs.io/
Project-URL: Repository, https://github.com/axliupore/textsentinel
Project-URL: Issues, https://github.com/axliupore/textsentinel/issues
Project-URL: Changelog, https://github.com/axliupore/textsentinel/blob/main/CHANGELOG.md
Keywords: nlp,文本质量,数据清洗,数据过滤,lightgbm,训练数据,语料过滤,aigc
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Text Processing :: Linguistic
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: scipy>=1.10
Requires-Dist: scikit-learn>=1.3
Requires-Dist: lightgbm>=4.0
Provides-Extra: train
Requires-Dist: lightgbm>=4.0; extra == "train"
Requires-Dist: scikit-learn>=1.3; extra == "train"
Provides-Extra: cli
Requires-Dist: rich>=13.0; extra == "cli"
Requires-Dist: tqdm>=4.65; extra == "cli"
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: pytest-xdist>=3.3; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=1.7; extra == "dev"
Requires-Dist: black>=23.10; extra == "dev"
Requires-Dist: isort>=5.12; extra == "dev"
Requires-Dist: types-setuptools; extra == "dev"
Dynamic: license-file

<div align="center">

# textsentinel

**面向训练语料的工业级文本质量分类器**

[![PyPI](https://img.shields.io/pypi/v/textsentinel.svg?color=blue)](https://pypi.org/project/textsentinel/)
[![Python](https://img.shields.io/pypi/pyversions/textsentinel.svg)](https://pypi.org/project/textsentinel/)
[![License](https://img.shields.io/github/license/axliupore/textsentinel.svg)](LICENSE)
[![CI](https://github.com/axliupore/textsentinel/actions/workflows/ci.yml/badge.svg)](https://github.com/axliupore/textsentinel/actions)
[![codecov](https://codecov.io/gh/axliupore/textsentinel/branch/main/graph/badge.svg)](https://codecov.io/gh/axliupore/textsentinel)
[![Docs](https://img.shields.io/badge/docs-mkdocs--material-blue.svg)](https://textsentinel.readthedocs.io/)
[![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)

一个 61 维手工特征提取器 + LightGBM 分类器，用于从中英混合语料中筛除损坏、跑题或低信号的段落 —— 通常作为 LLM 微调 / 预训练数据准备阶段的前置过滤器。

<p align="center"><img src="./assets/pipeline-overview.png" alt="TextSentinel Pipeline Overview" width="800"></p>

[为什么做这个](#为什么做这个) • [特性](#特性) • [安装](#安装) • [快速上手](#快速上手) • [文档](https://textsentinel.readthedocs.io/)

</div>

---

## 为什么做这个

在准备中文学术语料给 LLM 训练时，原始段落里经常混着这些"垃圾"：

- CNKI PDF 提取遗留的 PUA / 脚注区字符
- 代码块、Shell 命令、IP 地址、文件路径
- LaTeX 公式 dump、行内公式残留
- 破碎的参考文献片段
- OCR 乱码字形
- 漏进中文流水线的纯英文段落
- 展平的回归系数表（数字洪流）
- 标点粘连英文单词（如 `.And`）

61 维手工特征提取器将文本中的结构性信号（如 PUA 字符、代码标记、表格结构、引用密度、熵值等）编码为固定维度的向量，LightGBM 分类器在此基础上学习软边界，输出 [0, 1] 质量分数。附带一个小 CLI 做批量过滤。

## 特性

- **61 维手工特征**，分 5 个主题组（基础统计、表格结构、引用、语言风格、PDF 提取损坏）。
- **LightGBM booster**，特征顺序确定性 —— 跨进程、跨机器反复加载结果稳定。
- **CLI** —— `tqd score`、`tqd filter`、`tqd info`、`tqd-download`、`tqd-train`。
- **全量类型提示**，`py.typed`（PEP 561）。
- **无深度学习依赖** —— 纯 NumPy + scikit-learn + LightGBM。
- **可复现** —— 固定随机种子，特征提取确定性。
- **Linux / macOS / Windows + Python 3.10 / 3.11 / 3.12 全平台测试通过。**

## 安装

```bash
pip install textsentinel
```

如需训练、CLI、进度条等可选依赖：

```bash
pip install "textsentinel[cli,train]"
```

## 快速上手

下载预训练模型，然后三行代码完成打分：

```bash
tqd-download --dest models/model.txt
```

```python
from tqd import QualityClassifier

clf = QualityClassifier.from_pretrained("models/model.txt")
print(clf.predict("用户通信需求提升和通信技术革新是移动通信系统演进的源动力。"))
# 0.92
print(clf.should_keep("```python\nprint(1)\n```"))
# False
```

过滤 JSONL 语料：

```bash
tqd filter --model models/model.txt \
    -i corpus.jsonl \
    -k corpus.kept.jsonl \
    -d corpus.dropped.jsonl
```

在自有标注数据上重新训练：

```bash
tqd-train --labeled data/labeled.jsonl --output models/my_model.txt
```

## 性能指标

| 指标 | 数值 |
|------|-----:|
| 5 折 CV AUC（均值） | 0.9913 |
| 5 折 CV AUC（标准差） | 0.0003 |
| 测试集 AUC | 0.9913 |
| 测试集准确率（阈值 0.70） | 0.9647 |
| 测试集样本数 | 31,221 |
| 训练集样本数 | 145,694 |
| 正例占比 | 0.880 |

完整 61 维特征说明见 [`docs/features.md`](docs/features.md)，超参调优建议见 [`docs/training.md`](docs/training.md)。

## 目录结构

```
textsentinel/
├── tqd/                          # Python 包（导入名）
│   ├── __init__.py                # 公开 API
│   ├── _version.py
│   ├── classifier.py              # LightGBM 包装
│   ├── features.py                # 61 维特征提取
│   ├── training.py                # 交叉验证 + 阈值寻优
│   ├── download.py                # 模型下载
│   ├── cli.py                     # `tqd` 命令
│   ├── config.py                  # YAML 配置加载
│   ├── exceptions.py              # 异常体系
│   ├── logging.py                 # 日志
│   └── py.typed
├── tests/                         # pytest 测试（单元 + 集成）
├── examples/                      # 可运行示例
├── docs/                          # mkdocs-material 站点
├── configs/                       # 默认 YAML 配置
├── assets/                        # 静态资源
├── models/                        # 模型目录（默认空，按需下载）
├── scripts/                       # 辅助脚本（mkdocs 等）
├── .github/                       # CI、Issue 模板、Dependabot
├── pyproject.toml                 # 构建 + 工具配置
├── mkdocs.yml                     # 文档配置
├── README.md                      # 简体中文（你在这里）
├── CHANGELOG.md
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
├── LICENSE
└── CITATION.cff
```
    
## 架构

<p align="center"><img src="./assets/technical-architecture.png" alt="TextSentinel Technical Architecture" width="800"></p>

### 模块布局

```
tqd/
├── __init__.py        # 公开 API 转发
├── _version.py        # 版本常量
├── classifier.py      # QualityClassifier：LightGBM 包装
├── cli.py             # `tqd` 命令行入口
├── config.py          # YAML 配置加载
├── download.py        # 模型下载工具（`tqd-download`）
├── exceptions.py      # 异常体系
├── features.py        # 61 维特征提取
├── logging.py         # 日志配置
├── training.py        # 训练流水线（`tqd-train`）
└── py.typed           # PEP 561 标记
```

### 数据流

**推理：**

1. `QualityClassifier.from_pretrained(path)` —— 加载 LightGBM `Booster` 和附带的 `meta.json`（含 `threshold` 和 `feature_names`）。一次性成本（~10 ms），线程间共享安全。
2. `clf.predict(text)` —— 计算 61 维特征向量（内部 `functools.lru_cache` 缓存），跑 booster。
3. `clf.should_keep(text)` —— 把得分与 `clf.threshold` 比对。

特征缓存（`lru_cache(maxsize=4096)`）对同一段文本被反复打分的场景（例如批量任务重跑）特别有用。

**训练：**

1. `load_jsonl_texts(path)` —— 加载已标注的 JSONL 数据。
2. `train_lightgbm(X, y, cv_folds=5)` —— 5 折 CV 训 5 个 booster，然后在全部数据上训最终 booster。
3. `tune_threshold(booster, X_val, y_val, target_recall=0.95)` —— 在满足召回率目标的前提下，挑精度最高的阈值。
4. `clf.save(path)` —— 写 `path` 和 `path.meta.json`，供后续 `from_pretrained` 使用。

### 设计决策

- **61 维特征向量，不需要 GB-level 模型。** 一个梯度提升树推理亚毫秒且完全确定性。
- **特征名是 API 契约。** `FEATURE_NAMES` 的顺序是模型文件格式的一部分，改动顺序必须重训。
- **纯 NumPy 推理** —— 不依赖 torch / GPU。`pip install` 后随便哪台机器都能跑。
- **CLI 优先。** 高频用户用 shell；`tqd` 覆盖最常见场景（score、filter、info），免写 Python。

### 错误体系

所有异常都继承自 `TextSentinelError`：

| 异常 | 触发条件 |
|------|---------|
| `ModelFileError` | 模型文件缺失、不可读，或在占位分类器上调 `.predict()`。 |
| `FeatureDimensionMismatchError` | 保存的模型特征数与当前代码不一致。 |
| `ConfigurationError` | YAML 配置缺失或格式错误。 |
| `DownloadError` | 模型下载时网络或校验失败。 |

## 贡献

欢迎所有形式的贡献 —— 提 Issue、修文档、加功能、改性能都行。详见 [`CONTRIBUTING.md`](CONTRIBUTING.md)。参与即表示同意遵守我们的 [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md)。

## 引用

如果在学术工作中使用本库，请通过 [`CITATION.cff`](CITATION.cff) 引用。示例 BibTeX：

```bibtex
@software{axliupore_textsentinel,
  author = {axliupore},
  title  = {textsentinel：面向训练语料的文本质量分类器},
  year   = {2026},
  url    = {https://github.com/axliupore/textsentinel},
}
```

## 开源协议

Apache 2.0 —— 见 [`LICENSE`](LICENSE)。
