sdpy-kit 0.1.13__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/PKG-INFO +111 -6
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/README.md +107 -5
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/__init__.py +1 -1
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/config/kit_config.py +21 -0
- sdpy_kit-0.2.0/kit/marker_kit.py +548 -0
- sdpy_kit-0.2.0/kit/wx_article_kit.py +847 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/pyproject.toml +3 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/.gitignore +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/__init__.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/base_service.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/chat_service.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/embedding_service.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/exceptions.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/failover.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/image_service.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/model_builder.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/model_client.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/pool.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/profiles.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/rerank_service.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/runner.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/ai/types.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/anydoc_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/common_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/config/__init__.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/config/log_config.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/__init__.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/base_db_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/crud.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/engine.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/exceptions.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/models/__init__.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/models/base.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/mysql_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/pg_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/query.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/session.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/sqlite_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/db/transaction.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/docx_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/file_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/mcp_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/md2doc_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/mineru_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/redis_kit.py +0 -0
- {sdpy_kit-0.1.13 → sdpy_kit-0.2.0}/kit/zvec_kit.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sdpy-kit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: SDPY Kit——统一数据库访问层(PG/MySQL/SQLite)与 AI/MCP/Redis/文件/文档/向量工具集
|
|
5
5
|
Author-email: Clark <changhongyuan@126.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -30,6 +30,7 @@ Requires-Dist: fastmcp>=4.0.5; extra == 'all'
|
|
|
30
30
|
Requires-Dist: firecrawl-anydoc>=0.2.4; extra == 'all'
|
|
31
31
|
Requires-Dist: httpx>=0.28.1; extra == 'all'
|
|
32
32
|
Requires-Dist: markdown-it-py>=4.2.0; extra == 'all'
|
|
33
|
+
Requires-Dist: marker-pdf[full]>=2.0.0; extra == 'all'
|
|
33
34
|
Requires-Dist: numpy>=2.5.3; extra == 'all'
|
|
34
35
|
Requires-Dist: pikepdf>=10.13.0; extra == 'all'
|
|
35
36
|
Requires-Dist: pimd[pdfa]>=2.2.5; extra == 'all'
|
|
@@ -45,6 +46,8 @@ Requires-Dist: firecrawl-anydoc>=0.2.4; extra == 'anydoc'
|
|
|
45
46
|
Requires-Dist: pikepdf>=10.13.0; extra == 'anydoc'
|
|
46
47
|
Provides-Extra: docx
|
|
47
48
|
Requires-Dist: docxtpl>=0.20.2; extra == 'docx'
|
|
49
|
+
Provides-Extra: marker
|
|
50
|
+
Requires-Dist: marker-pdf[full]>=2.0.0; extra == 'marker'
|
|
48
51
|
Provides-Extra: mcp
|
|
49
52
|
Requires-Dist: fastmcp>=4.0.5; extra == 'mcp'
|
|
50
53
|
Provides-Extra: md2doc
|
|
@@ -72,7 +75,7 @@ SDPY 统一工具集(Kit 体系),供 Python 项目开箱即用:
|
|
|
72
75
|
- **统一数据库访问层**:PostgreSQL / MySQL / SQLite,三个 Kit API 完全一致,切换数据库只改一行 import;
|
|
73
76
|
- **AI 多模型服务池**:chat / embedding / rerank / image 四类能力,多厂商候选链 + 故障自动转移;
|
|
74
77
|
- **MCP 客户端**:streamable-http / sse 双传输,档案驱动多服务器;
|
|
75
|
-
- **工具集**:Redis / 文件 / 雪花 ID / 文档互转 / Word 模板填充 / MinerU 解析 /
|
|
78
|
+
- **工具集**:Redis / 文件 / 雪花 ID / 文档互转 / Word 模板填充 / MinerU 解析 / Marker 本地解析(md + images) / 向量库 / 微信公众号文章抓取存储。
|
|
76
79
|
|
|
77
80
|
> 要求 Python 3.13+
|
|
78
81
|
|
|
@@ -91,7 +94,9 @@ SDPY 统一工具集(Kit 体系),供 Python 项目开箱即用:
|
|
|
91
94
|
| `kit.docx_kit` | `DocxKit` | Word 模板动态填充(章节 / 列表 / 表格) | `docx` |
|
|
92
95
|
| `kit.md2doc_kit` | `Md2DocKit` | Markdown → Word / PDF / HTML | `md2doc` |
|
|
93
96
|
| `kit.mineru_kit` | `MinerUKit` | MinerU 文档解析(精准 + Agent 轻量) | `mineru` |
|
|
97
|
+
| `kit.marker_kit` | `MarkerKit` | 本地文档解析(PDF / 图片 / Office → Markdown + Images) | `marker` |
|
|
94
98
|
| `kit.zvec_kit` | `ZvecKit` | zvec 本地向量库 | `zvec` |
|
|
99
|
+
| `kit.wx_article_kit` | `WxArticleKit` | 微信公众号文章 → Markdown + 图片转存 | 无 |
|
|
95
100
|
|
|
96
101
|
## 安装
|
|
97
102
|
|
|
@@ -116,6 +121,7 @@ uv add sdpy-kit
|
|
|
116
121
|
| `anydoc` | AnyDocKit 文档转 Markdown(firecrawl-anydoc + pikepdf) | `pip install "sdpy-kit[anydoc]"` |
|
|
117
122
|
| `docx` | DocxKit 模板动态填充(docxtpl) | `pip install "sdpy-kit[docx]"` |
|
|
118
123
|
| `mineru` | MinerUKit 解析 API(精准解析 + Agent 轻量解析) | `pip install "sdpy-kit[mineru]"` |
|
|
124
|
+
| `marker` | MarkerKit 本地文档解析(marker-pdf[full] → Markdown + Images,依赖体积大) | `pip install "sdpy-kit[marker]"` |
|
|
119
125
|
| `all` | 全部能力 | `pip install "sdpy-kit[all]"` |
|
|
120
126
|
|
|
121
127
|
## 配置(.env)
|
|
@@ -160,11 +166,17 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
160
166
|
|
|
161
167
|
# MinerU(仅精准解析需要 Key,Agent 轻量解析免登录)
|
|
162
168
|
# MINERU_API_KEY=
|
|
169
|
+
|
|
170
|
+
# Marker(本地解析,可选依赖 sdpy-kit[marker])
|
|
171
|
+
# MARKER_MODE=fast # None=按设备自动(GPU→balanced / CPU、MPS→fast)
|
|
172
|
+
# MARKER_HF_ENDPOINT=https://hf-mirror.com
|
|
173
|
+
# MARKER_HF_DISABLE_XET=true
|
|
174
|
+
# MARKER_LLAMA_CPP_BINARY=
|
|
163
175
|
```
|
|
164
176
|
|
|
165
177
|
### 环境变量 ↔ 能力对照表
|
|
166
178
|
|
|
167
|
-
> 表中未出现的模块(`kit.common_kit`、`kit.docx_kit`、`kit.md2doc_kit`)不读取任何环境变量。
|
|
179
|
+
> 表中未出现的模块(`kit.common_kit`、`kit.docx_kit`、`kit.md2doc_kit`、`kit.wx_article_kit`)不读取任何环境变量。
|
|
168
180
|
|
|
169
181
|
**基础与日志**(影响 `kit.config` 及所有模块的日志输出)
|
|
170
182
|
|
|
@@ -224,7 +236,6 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
224
236
|
| 环境变量 | 默认值 | 作用 |
|
|
225
237
|
|----------|--------|------|
|
|
226
238
|
| `AI_MODELS_CONFIG_PATH` | `./config/ai_models.json` | 档案文件位置;文件不存在时调用抛 `AIConfigError` |
|
|
227
|
-
| *(已移除)* `AI_CHAT_PROFILES` 等 4 个 | — | 候选链顺序覆盖变量自 **0.1.13** 起移除:链顺序固定为「`default_profile` 打头 + JSON 声明顺序」;`.env` 中残留旧变量会被静默忽略(`Settings` 为 `extra="ignore"`) |
|
|
228
239
|
| `KIT_AI_CHAIN_TIMEOUT` | 未设置 | 全局整链预算(秒)= 门面同步等待上限。⚠ **不是 `Settings` 字段**,由代码直读 `os.environ`,无类型/范围校验,非法值仅告警后回退 |
|
|
229
240
|
| *(密钥,变量名由档案决定)* | 无 | 名字写在 `ai_models.json` 各档案的 `api_key` 字段(如 `SILICONFLOW_API_KEY`),值放 `.env` 或系统环境变量。未配置的档案会被剔除出候选链;该类型全部未配置则调用失败 |
|
|
230
241
|
|
|
@@ -247,6 +258,17 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
247
258
|
| `MINERU_POLL_INTERVAL` | `2.0`(≥0.5) | 任务轮询间隔 |
|
|
248
259
|
| `MINERU_MAX_WAIT` | `600`(≥10) | 轮询总超时,超时抛 `MinerUError` |
|
|
249
260
|
|
|
261
|
+
**Marker** → `kit.marker_kit`
|
|
262
|
+
|
|
263
|
+
| 环境变量 | 默认值 | 作用 |
|
|
264
|
+
|----------|--------|------|
|
|
265
|
+
| `MARKER_MODE` | 无(不写入 config) | 解析模式 `balanced` / `fast`;不配置则由 marker 按设备自动选择(GPU→balanced,CPU、MPS→fast) |
|
|
266
|
+
| `MARKER_HF_ENDPOINT` | `https://hf-mirror.com` | 模型权重下载入口(国内镜像);置空则用 HuggingFace 官方源 |
|
|
267
|
+
| `MARKER_HF_DISABLE_XET` | `true` | 禁用 HF Xet 存储后端(国内镜像不支持,开启会导致权重下载挂起) |
|
|
268
|
+
| `MARKER_LLAMA_CPP_BINARY` | 无 | `llama-server` 路径(非 NVIDIA 平台完整 VLM 能力);未设置时沿用系统 `LLAMA_CPP_BINARY` |
|
|
269
|
+
|
|
270
|
+
> 这四项由 kit 在**导入 marker 之前**经 `os.environ.setdefault` 应用:仅当用户未显式设置对应环境变量时生效,不覆盖显式配置。
|
|
271
|
+
|
|
250
272
|
**云 OCR**(任何 `ocr="hosted"` 的转换)→ `kit.anydoc_kit`
|
|
251
273
|
|
|
252
274
|
| 环境变量 | 默认值 | 作用 |
|
|
@@ -261,7 +283,7 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
261
283
|
| ① Settings 变量 | 固定,kit 定义 | 上表中除 `KIT_AI_CHAIN_TIMEOUT` 与密钥类之外的全部 | pydantic-settings 读 `.env` 与真实环境变量(后者优先),带类型与范围校验,缺失用默认值 |
|
|
262
284
|
| ② 直读变量 | 固定,kit 代码直接读 `os.environ` | `KIT_AI_CHAIN_TIMEOUT` | 无类型校验,非法值告警后回退 |
|
|
263
285
|
| ③ 档案声明变量 | **动态**,名字写在 JSON 里 | AI 的 `api_key`、MCP 的 `token_env` | **名字进 JSON、值进 `.env`**——所以档案文件可以安全入库,密钥留在环境里 |
|
|
264
|
-
| ④ 第三方库变量 | 由依赖库定义 | `FIRECRAWL_API_KEY`、`FIRECRAWL_API_URL` | kit 只透传 `None
|
|
286
|
+
| ④ 第三方库变量 | 由依赖库定义 | `FIRECRAWL_API_KEY`、`FIRECRAWL_API_URL`(anydoc);`HF_ENDPOINT` / `HF_HUB_DISABLE_XET` / `LLAMA_CPP_BINARY`(marker) | anydoc:kit 只透传 `None`,由其自行回落;marker:kit 在导入前按 `MARKER_*` 配置做 `os.environ.setdefault`(不覆盖显式设置) |
|
|
265
287
|
|
|
266
288
|
### 密钥解析优先级
|
|
267
289
|
|
|
@@ -277,7 +299,8 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
277
299
|
|
|
278
300
|
| 改动内容 | 生效时机 |
|
|
279
301
|
|----------|----------|
|
|
280
|
-
| `LOG_*`、`DB_*`、`MYSQL_*`、`REDIS_*`、`FILE_STORAGE_ROOT`、`ZVEC_*`、`MINERU_
|
|
302
|
+
| `LOG_*`、`DB_*`、`MYSQL_*`、`REDIS_*`、`FILE_STORAGE_ROOT`、`ZVEC_*`、`MINERU_*`、`MARKER_MODE` | `get_settings()` 带 `lru_cache`,进程内首次读取后固定 → **重启进程**(或调用 `AI.reload_config()`,它会顺带清空该缓存) |
|
|
303
|
+
| `MARKER_HF_ENDPOINT` / `MARKER_HF_DISABLE_XET` / `MARKER_LLAMA_CPP_BINARY` | 仅在 `import kit.marker_kit` 时经 `os.environ.setdefault` 应用 → 改动需**重启进程**重新导入模块 |
|
|
281
304
|
| AI 密钥写在 `.env` 里 | `.env` 只在加载档案时注入一次 → 重启,或 `AI.reload_config(reload_file=True)` |
|
|
282
305
|
| AI 密钥由自己写入 `os.environ` | `AI.reload_config()`(默认 `reload_file=False`,只重读 `os.environ`) |
|
|
283
306
|
| `ai_models.json`(增删档案、换 model) | `AI.reload_config(reload_file=True)` |
|
|
@@ -810,6 +833,46 @@ if r.state == "done":
|
|
|
810
833
|
|
|
811
834
|
---
|
|
812
835
|
|
|
836
|
+
## kit.marker_kit —— 本地文档解析(Markdown + Images)
|
|
837
|
+
|
|
838
|
+
安装:`pip install "sdpy-kit[marker]"`(依赖 `marker-pdf[full]`,含 torch 等 80+ 包,体积较大)
|
|
839
|
+
|
|
840
|
+
```python
|
|
841
|
+
from kit.marker_kit import MarkerKit
|
|
842
|
+
|
|
843
|
+
# 落盘 md + images(推荐):源文件同目录下建同名子目录
|
|
844
|
+
md_path = MarkerKit.convert_to_dir("report.pdf") # -> report/report.md + 图片
|
|
845
|
+
md_path = MarkerKit.convert_to_dir("report.pdf", "out/doc") # 指定产物目录
|
|
846
|
+
|
|
847
|
+
# 只取 Markdown 文本(图片不落盘)
|
|
848
|
+
md = MarkerKit.convert_to_md("report.pdf")
|
|
849
|
+
|
|
850
|
+
# 安全转换(不抛异常,返回结果对象)
|
|
851
|
+
result = MarkerKit.convert("report.pdf", "out/doc")
|
|
852
|
+
if result.success:
|
|
853
|
+
print(result.md_path, len(result.image_paths), result.page_count)
|
|
854
|
+
|
|
855
|
+
# 跳过 VLM(无需 llama.cpp)
|
|
856
|
+
md = MarkerKit.convert_to_md("scan.pdf", disable_ocr=True)
|
|
857
|
+
|
|
858
|
+
MarkerKit.shutdown() # 释放模型与推理服务(幂等)
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
| 方法 | 说明 |
|
|
862
|
+
|------|------|
|
|
863
|
+
| `is_supported(file_path) -> bool` | 扩展名白名单(pdf / 图片 / docx / pptx / xlsx / html / epub) |
|
|
864
|
+
| `convert_to_md(file_path, *, mode=None, force_ocr=None, disable_ocr=None, page_range=None) -> str` | 解析并返回 Markdown 文本(图片不落盘) |
|
|
865
|
+
| `convert_to_dir(src_path, output_dir=None, *, mode=None, force_ocr=None, disable_ocr=None, page_range=None, extract_images=True) -> str` | 解析并落盘 md + images,返回 md 绝对路径 |
|
|
866
|
+
| `convert(src_path, output_dir=None, *, ...) -> MarkerResult` | 安全版:失败封装为 `MarkerResult`,不抛异常 |
|
|
867
|
+
| `shutdown() -> None` | 释放模型与共享推理服务(幂等) |
|
|
868
|
+
|
|
869
|
+
> 产物:`<output_dir>/<源文件名>.md` + 图片文件(md 内相对路径引用),**不生成** `_meta.json`。
|
|
870
|
+
> 结果类型:`MarkerResult`(`success` / `markdown` / `file_path` / `output_dir` / `md_path` / `image_paths` / `page_count` / `error`);异常:`MarkerError`。
|
|
871
|
+
> `mode` 缺省时不写入配置,交由 marker 按设备自动选择;首次使用会下载模型权重(默认走 `MARKER_HF_ENDPOINT` 镜像)。
|
|
872
|
+
> 非 NVIDIA 平台完整 VLM 能力(公式 / 扫描页 OCR)需 llama.cpp 的 `llama-server`,否则用 `disable_ocr=True` 跳过。
|
|
873
|
+
|
|
874
|
+
---
|
|
875
|
+
|
|
813
876
|
## kit.zvec_kit —— 本地向量库
|
|
814
877
|
|
|
815
878
|
安装:`pip install "sdpy-kit[zvec]"`
|
|
@@ -838,6 +901,48 @@ ZvecKit.flush("docs")
|
|
|
838
901
|
|
|
839
902
|
---
|
|
840
903
|
|
|
904
|
+
## kit.wx_article_kit —— 微信公众号文章抓取存储
|
|
905
|
+
|
|
906
|
+
零第三方依赖(标准库 `urllib` + 内置 HTML→Markdown 转换器),**无需 extra**,按需 import:
|
|
907
|
+
|
|
908
|
+
```python
|
|
909
|
+
from kit.wx_article_kit import WxArticleKit
|
|
910
|
+
|
|
911
|
+
# 抓取解析(不落盘)
|
|
912
|
+
result = WxArticleKit.fetch("https://mp.weixin.qq.com/s/xxxx")
|
|
913
|
+
if result.ok:
|
|
914
|
+
print(result.info.title, result.info.author, result.info.publish_time)
|
|
915
|
+
|
|
916
|
+
# 抓取并存储:<output_dir>/<file_name>/ 下 <file_name>.md + images/
|
|
917
|
+
saved = WxArticleKit.save(url, output_dir="./output", file_name="12345")
|
|
918
|
+
print(saved.md_path, saved.images_saved)
|
|
919
|
+
|
|
920
|
+
# 需要结构化元信息时再产出 meta.json(默认不产出)
|
|
921
|
+
WxArticleKit.save(url, "./output", "12345", write_meta=True)
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
| 方法 | 说明 |
|
|
925
|
+
|------|------|
|
|
926
|
+
| `fetch(url, timeout=20.0) -> ArticleResult` | 抓取并解析正文(不落盘);结果对象字段 `ok` / `error` / `info`(`ArticleInfo`)/ `markdown` |
|
|
927
|
+
| `save(url, output_dir, file_name, write_meta=False, timeout=20.0) -> SavedOutput` | 抓取并存储到 `<output_dir>/<file_name>/`;结果对象字段 `ok` / `error` / `output_dir` / `md_path` / `images_dir` / `title` / `images_saved` |
|
|
928
|
+
|
|
929
|
+
落盘结构:
|
|
930
|
+
|
|
931
|
+
```
|
|
932
|
+
<output_dir>/<file_name>/
|
|
933
|
+
├── <file_name>.md # 正文 Markdown(YAML 头:title / author / publish_time / source_url)
|
|
934
|
+
├── images/ # 图片转存(NNN.ext,正文引用已本地化)
|
|
935
|
+
└── meta.json # 可选:结构化元信息(write_meta=True 时产出)
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
- 元信息默认随 Markdown 的 YAML 头落盘(头部 `publish_time` 为中文日期,如 `2026年8月4日`);
|
|
939
|
+
`ArticleInfo.publish_time` 与 `meta.json` 内仍为 ISO 8601(结构化数据)。
|
|
940
|
+
- 无登录态抓取:命中微信风控(环境异常 / 访问过于频繁)时返回 `ok=False` + 原因,不破解验证码;
|
|
941
|
+
抓取或图片下载失败不抛异常,单张图片失败时正文保留原远程 URL。
|
|
942
|
+
- 同名子目录**覆盖写**(不追加序号);`file_name` 带 `.md` 后缀会自动去除,为空则抛 `ValueError`。
|
|
943
|
+
|
|
944
|
+
---
|
|
945
|
+
|
|
841
946
|
## AI / MCP 档案文件
|
|
842
947
|
|
|
843
948
|
AI 与 MCP 功能需要在项目根目录提供两个 JSON 档案文件:
|
|
@@ -5,7 +5,7 @@ SDPY 统一工具集(Kit 体系),供 Python 项目开箱即用:
|
|
|
5
5
|
- **统一数据库访问层**:PostgreSQL / MySQL / SQLite,三个 Kit API 完全一致,切换数据库只改一行 import;
|
|
6
6
|
- **AI 多模型服务池**:chat / embedding / rerank / image 四类能力,多厂商候选链 + 故障自动转移;
|
|
7
7
|
- **MCP 客户端**:streamable-http / sse 双传输,档案驱动多服务器;
|
|
8
|
-
- **工具集**:Redis / 文件 / 雪花 ID / 文档互转 / Word 模板填充 / MinerU 解析 /
|
|
8
|
+
- **工具集**:Redis / 文件 / 雪花 ID / 文档互转 / Word 模板填充 / MinerU 解析 / Marker 本地解析(md + images) / 向量库 / 微信公众号文章抓取存储。
|
|
9
9
|
|
|
10
10
|
> 要求 Python 3.13+
|
|
11
11
|
|
|
@@ -24,7 +24,9 @@ SDPY 统一工具集(Kit 体系),供 Python 项目开箱即用:
|
|
|
24
24
|
| `kit.docx_kit` | `DocxKit` | Word 模板动态填充(章节 / 列表 / 表格) | `docx` |
|
|
25
25
|
| `kit.md2doc_kit` | `Md2DocKit` | Markdown → Word / PDF / HTML | `md2doc` |
|
|
26
26
|
| `kit.mineru_kit` | `MinerUKit` | MinerU 文档解析(精准 + Agent 轻量) | `mineru` |
|
|
27
|
+
| `kit.marker_kit` | `MarkerKit` | 本地文档解析(PDF / 图片 / Office → Markdown + Images) | `marker` |
|
|
27
28
|
| `kit.zvec_kit` | `ZvecKit` | zvec 本地向量库 | `zvec` |
|
|
29
|
+
| `kit.wx_article_kit` | `WxArticleKit` | 微信公众号文章 → Markdown + 图片转存 | 无 |
|
|
28
30
|
|
|
29
31
|
## 安装
|
|
30
32
|
|
|
@@ -49,6 +51,7 @@ uv add sdpy-kit
|
|
|
49
51
|
| `anydoc` | AnyDocKit 文档转 Markdown(firecrawl-anydoc + pikepdf) | `pip install "sdpy-kit[anydoc]"` |
|
|
50
52
|
| `docx` | DocxKit 模板动态填充(docxtpl) | `pip install "sdpy-kit[docx]"` |
|
|
51
53
|
| `mineru` | MinerUKit 解析 API(精准解析 + Agent 轻量解析) | `pip install "sdpy-kit[mineru]"` |
|
|
54
|
+
| `marker` | MarkerKit 本地文档解析(marker-pdf[full] → Markdown + Images,依赖体积大) | `pip install "sdpy-kit[marker]"` |
|
|
52
55
|
| `all` | 全部能力 | `pip install "sdpy-kit[all]"` |
|
|
53
56
|
|
|
54
57
|
## 配置(.env)
|
|
@@ -93,11 +96,17 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
93
96
|
|
|
94
97
|
# MinerU(仅精准解析需要 Key,Agent 轻量解析免登录)
|
|
95
98
|
# MINERU_API_KEY=
|
|
99
|
+
|
|
100
|
+
# Marker(本地解析,可选依赖 sdpy-kit[marker])
|
|
101
|
+
# MARKER_MODE=fast # None=按设备自动(GPU→balanced / CPU、MPS→fast)
|
|
102
|
+
# MARKER_HF_ENDPOINT=https://hf-mirror.com
|
|
103
|
+
# MARKER_HF_DISABLE_XET=true
|
|
104
|
+
# MARKER_LLAMA_CPP_BINARY=
|
|
96
105
|
```
|
|
97
106
|
|
|
98
107
|
### 环境变量 ↔ 能力对照表
|
|
99
108
|
|
|
100
|
-
> 表中未出现的模块(`kit.common_kit`、`kit.docx_kit`、`kit.md2doc_kit`)不读取任何环境变量。
|
|
109
|
+
> 表中未出现的模块(`kit.common_kit`、`kit.docx_kit`、`kit.md2doc_kit`、`kit.wx_article_kit`)不读取任何环境变量。
|
|
101
110
|
|
|
102
111
|
**基础与日志**(影响 `kit.config` 及所有模块的日志输出)
|
|
103
112
|
|
|
@@ -157,7 +166,6 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
157
166
|
| 环境变量 | 默认值 | 作用 |
|
|
158
167
|
|----------|--------|------|
|
|
159
168
|
| `AI_MODELS_CONFIG_PATH` | `./config/ai_models.json` | 档案文件位置;文件不存在时调用抛 `AIConfigError` |
|
|
160
|
-
| *(已移除)* `AI_CHAT_PROFILES` 等 4 个 | — | 候选链顺序覆盖变量自 **0.1.13** 起移除:链顺序固定为「`default_profile` 打头 + JSON 声明顺序」;`.env` 中残留旧变量会被静默忽略(`Settings` 为 `extra="ignore"`) |
|
|
161
169
|
| `KIT_AI_CHAIN_TIMEOUT` | 未设置 | 全局整链预算(秒)= 门面同步等待上限。⚠ **不是 `Settings` 字段**,由代码直读 `os.environ`,无类型/范围校验,非法值仅告警后回退 |
|
|
162
170
|
| *(密钥,变量名由档案决定)* | 无 | 名字写在 `ai_models.json` 各档案的 `api_key` 字段(如 `SILICONFLOW_API_KEY`),值放 `.env` 或系统环境变量。未配置的档案会被剔除出候选链;该类型全部未配置则调用失败 |
|
|
163
171
|
|
|
@@ -180,6 +188,17 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
180
188
|
| `MINERU_POLL_INTERVAL` | `2.0`(≥0.5) | 任务轮询间隔 |
|
|
181
189
|
| `MINERU_MAX_WAIT` | `600`(≥10) | 轮询总超时,超时抛 `MinerUError` |
|
|
182
190
|
|
|
191
|
+
**Marker** → `kit.marker_kit`
|
|
192
|
+
|
|
193
|
+
| 环境变量 | 默认值 | 作用 |
|
|
194
|
+
|----------|--------|------|
|
|
195
|
+
| `MARKER_MODE` | 无(不写入 config) | 解析模式 `balanced` / `fast`;不配置则由 marker 按设备自动选择(GPU→balanced,CPU、MPS→fast) |
|
|
196
|
+
| `MARKER_HF_ENDPOINT` | `https://hf-mirror.com` | 模型权重下载入口(国内镜像);置空则用 HuggingFace 官方源 |
|
|
197
|
+
| `MARKER_HF_DISABLE_XET` | `true` | 禁用 HF Xet 存储后端(国内镜像不支持,开启会导致权重下载挂起) |
|
|
198
|
+
| `MARKER_LLAMA_CPP_BINARY` | 无 | `llama-server` 路径(非 NVIDIA 平台完整 VLM 能力);未设置时沿用系统 `LLAMA_CPP_BINARY` |
|
|
199
|
+
|
|
200
|
+
> 这四项由 kit 在**导入 marker 之前**经 `os.environ.setdefault` 应用:仅当用户未显式设置对应环境变量时生效,不覆盖显式配置。
|
|
201
|
+
|
|
183
202
|
**云 OCR**(任何 `ocr="hosted"` 的转换)→ `kit.anydoc_kit`
|
|
184
203
|
|
|
185
204
|
| 环境变量 | 默认值 | 作用 |
|
|
@@ -194,7 +213,7 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
194
213
|
| ① Settings 变量 | 固定,kit 定义 | 上表中除 `KIT_AI_CHAIN_TIMEOUT` 与密钥类之外的全部 | pydantic-settings 读 `.env` 与真实环境变量(后者优先),带类型与范围校验,缺失用默认值 |
|
|
195
214
|
| ② 直读变量 | 固定,kit 代码直接读 `os.environ` | `KIT_AI_CHAIN_TIMEOUT` | 无类型校验,非法值告警后回退 |
|
|
196
215
|
| ③ 档案声明变量 | **动态**,名字写在 JSON 里 | AI 的 `api_key`、MCP 的 `token_env` | **名字进 JSON、值进 `.env`**——所以档案文件可以安全入库,密钥留在环境里 |
|
|
197
|
-
| ④ 第三方库变量 | 由依赖库定义 | `FIRECRAWL_API_KEY`、`FIRECRAWL_API_URL` | kit 只透传 `None
|
|
216
|
+
| ④ 第三方库变量 | 由依赖库定义 | `FIRECRAWL_API_KEY`、`FIRECRAWL_API_URL`(anydoc);`HF_ENDPOINT` / `HF_HUB_DISABLE_XET` / `LLAMA_CPP_BINARY`(marker) | anydoc:kit 只透传 `None`,由其自行回落;marker:kit 在导入前按 `MARKER_*` 配置做 `os.environ.setdefault`(不覆盖显式设置) |
|
|
198
217
|
|
|
199
218
|
### 密钥解析优先级
|
|
200
219
|
|
|
@@ -210,7 +229,8 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
210
229
|
|
|
211
230
|
| 改动内容 | 生效时机 |
|
|
212
231
|
|----------|----------|
|
|
213
|
-
| `LOG_*`、`DB_*`、`MYSQL_*`、`REDIS_*`、`FILE_STORAGE_ROOT`、`ZVEC_*`、`MINERU_
|
|
232
|
+
| `LOG_*`、`DB_*`、`MYSQL_*`、`REDIS_*`、`FILE_STORAGE_ROOT`、`ZVEC_*`、`MINERU_*`、`MARKER_MODE` | `get_settings()` 带 `lru_cache`,进程内首次读取后固定 → **重启进程**(或调用 `AI.reload_config()`,它会顺带清空该缓存) |
|
|
233
|
+
| `MARKER_HF_ENDPOINT` / `MARKER_HF_DISABLE_XET` / `MARKER_LLAMA_CPP_BINARY` | 仅在 `import kit.marker_kit` 时经 `os.environ.setdefault` 应用 → 改动需**重启进程**重新导入模块 |
|
|
214
234
|
| AI 密钥写在 `.env` 里 | `.env` 只在加载档案时注入一次 → 重启,或 `AI.reload_config(reload_file=True)` |
|
|
215
235
|
| AI 密钥由自己写入 `os.environ` | `AI.reload_config()`(默认 `reload_file=False`,只重读 `os.environ`) |
|
|
216
236
|
| `ai_models.json`(增删档案、换 model) | `AI.reload_config(reload_file=True)` |
|
|
@@ -743,6 +763,46 @@ if r.state == "done":
|
|
|
743
763
|
|
|
744
764
|
---
|
|
745
765
|
|
|
766
|
+
## kit.marker_kit —— 本地文档解析(Markdown + Images)
|
|
767
|
+
|
|
768
|
+
安装:`pip install "sdpy-kit[marker]"`(依赖 `marker-pdf[full]`,含 torch 等 80+ 包,体积较大)
|
|
769
|
+
|
|
770
|
+
```python
|
|
771
|
+
from kit.marker_kit import MarkerKit
|
|
772
|
+
|
|
773
|
+
# 落盘 md + images(推荐):源文件同目录下建同名子目录
|
|
774
|
+
md_path = MarkerKit.convert_to_dir("report.pdf") # -> report/report.md + 图片
|
|
775
|
+
md_path = MarkerKit.convert_to_dir("report.pdf", "out/doc") # 指定产物目录
|
|
776
|
+
|
|
777
|
+
# 只取 Markdown 文本(图片不落盘)
|
|
778
|
+
md = MarkerKit.convert_to_md("report.pdf")
|
|
779
|
+
|
|
780
|
+
# 安全转换(不抛异常,返回结果对象)
|
|
781
|
+
result = MarkerKit.convert("report.pdf", "out/doc")
|
|
782
|
+
if result.success:
|
|
783
|
+
print(result.md_path, len(result.image_paths), result.page_count)
|
|
784
|
+
|
|
785
|
+
# 跳过 VLM(无需 llama.cpp)
|
|
786
|
+
md = MarkerKit.convert_to_md("scan.pdf", disable_ocr=True)
|
|
787
|
+
|
|
788
|
+
MarkerKit.shutdown() # 释放模型与推理服务(幂等)
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
| 方法 | 说明 |
|
|
792
|
+
|------|------|
|
|
793
|
+
| `is_supported(file_path) -> bool` | 扩展名白名单(pdf / 图片 / docx / pptx / xlsx / html / epub) |
|
|
794
|
+
| `convert_to_md(file_path, *, mode=None, force_ocr=None, disable_ocr=None, page_range=None) -> str` | 解析并返回 Markdown 文本(图片不落盘) |
|
|
795
|
+
| `convert_to_dir(src_path, output_dir=None, *, mode=None, force_ocr=None, disable_ocr=None, page_range=None, extract_images=True) -> str` | 解析并落盘 md + images,返回 md 绝对路径 |
|
|
796
|
+
| `convert(src_path, output_dir=None, *, ...) -> MarkerResult` | 安全版:失败封装为 `MarkerResult`,不抛异常 |
|
|
797
|
+
| `shutdown() -> None` | 释放模型与共享推理服务(幂等) |
|
|
798
|
+
|
|
799
|
+
> 产物:`<output_dir>/<源文件名>.md` + 图片文件(md 内相对路径引用),**不生成** `_meta.json`。
|
|
800
|
+
> 结果类型:`MarkerResult`(`success` / `markdown` / `file_path` / `output_dir` / `md_path` / `image_paths` / `page_count` / `error`);异常:`MarkerError`。
|
|
801
|
+
> `mode` 缺省时不写入配置,交由 marker 按设备自动选择;首次使用会下载模型权重(默认走 `MARKER_HF_ENDPOINT` 镜像)。
|
|
802
|
+
> 非 NVIDIA 平台完整 VLM 能力(公式 / 扫描页 OCR)需 llama.cpp 的 `llama-server`,否则用 `disable_ocr=True` 跳过。
|
|
803
|
+
|
|
804
|
+
---
|
|
805
|
+
|
|
746
806
|
## kit.zvec_kit —— 本地向量库
|
|
747
807
|
|
|
748
808
|
安装:`pip install "sdpy-kit[zvec]"`
|
|
@@ -771,6 +831,48 @@ ZvecKit.flush("docs")
|
|
|
771
831
|
|
|
772
832
|
---
|
|
773
833
|
|
|
834
|
+
## kit.wx_article_kit —— 微信公众号文章抓取存储
|
|
835
|
+
|
|
836
|
+
零第三方依赖(标准库 `urllib` + 内置 HTML→Markdown 转换器),**无需 extra**,按需 import:
|
|
837
|
+
|
|
838
|
+
```python
|
|
839
|
+
from kit.wx_article_kit import WxArticleKit
|
|
840
|
+
|
|
841
|
+
# 抓取解析(不落盘)
|
|
842
|
+
result = WxArticleKit.fetch("https://mp.weixin.qq.com/s/xxxx")
|
|
843
|
+
if result.ok:
|
|
844
|
+
print(result.info.title, result.info.author, result.info.publish_time)
|
|
845
|
+
|
|
846
|
+
# 抓取并存储:<output_dir>/<file_name>/ 下 <file_name>.md + images/
|
|
847
|
+
saved = WxArticleKit.save(url, output_dir="./output", file_name="12345")
|
|
848
|
+
print(saved.md_path, saved.images_saved)
|
|
849
|
+
|
|
850
|
+
# 需要结构化元信息时再产出 meta.json(默认不产出)
|
|
851
|
+
WxArticleKit.save(url, "./output", "12345", write_meta=True)
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
| 方法 | 说明 |
|
|
855
|
+
|------|------|
|
|
856
|
+
| `fetch(url, timeout=20.0) -> ArticleResult` | 抓取并解析正文(不落盘);结果对象字段 `ok` / `error` / `info`(`ArticleInfo`)/ `markdown` |
|
|
857
|
+
| `save(url, output_dir, file_name, write_meta=False, timeout=20.0) -> SavedOutput` | 抓取并存储到 `<output_dir>/<file_name>/`;结果对象字段 `ok` / `error` / `output_dir` / `md_path` / `images_dir` / `title` / `images_saved` |
|
|
858
|
+
|
|
859
|
+
落盘结构:
|
|
860
|
+
|
|
861
|
+
```
|
|
862
|
+
<output_dir>/<file_name>/
|
|
863
|
+
├── <file_name>.md # 正文 Markdown(YAML 头:title / author / publish_time / source_url)
|
|
864
|
+
├── images/ # 图片转存(NNN.ext,正文引用已本地化)
|
|
865
|
+
└── meta.json # 可选:结构化元信息(write_meta=True 时产出)
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
- 元信息默认随 Markdown 的 YAML 头落盘(头部 `publish_time` 为中文日期,如 `2026年8月4日`);
|
|
869
|
+
`ArticleInfo.publish_time` 与 `meta.json` 内仍为 ISO 8601(结构化数据)。
|
|
870
|
+
- 无登录态抓取:命中微信风控(环境异常 / 访问过于频繁)时返回 `ok=False` + 原因,不破解验证码;
|
|
871
|
+
抓取或图片下载失败不抛异常,单张图片失败时正文保留原远程 URL。
|
|
872
|
+
- 同名子目录**覆盖写**(不追加序号);`file_name` 带 `.md` 后缀会自动去除,为空则抛 `ValueError`。
|
|
873
|
+
|
|
874
|
+
---
|
|
875
|
+
|
|
774
876
|
## AI / MCP 档案文件
|
|
775
877
|
|
|
776
878
|
AI 与 MCP 功能需要在项目根目录提供两个 JSON 档案文件:
|
|
@@ -121,6 +121,27 @@ class Settings(BaseSettings):
|
|
|
121
121
|
default=600, ge=10, description="任务轮询总超时(秒),超时抛 MinerUError"
|
|
122
122
|
)
|
|
123
123
|
|
|
124
|
+
# Marker 本地文档解析配置(marker-pdf,PDF→Markdown+Images,模型本地运行)
|
|
125
|
+
MARKER_MODE: str | None = Field(
|
|
126
|
+
default=None,
|
|
127
|
+
description=(
|
|
128
|
+
"解析模式:None=按设备自动(GPU→balanced,CPU/MPS→fast),"
|
|
129
|
+
"可设 balanced/fast"
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
MARKER_HF_ENDPOINT: str = Field(
|
|
133
|
+
default="https://hf-mirror.com",
|
|
134
|
+
description="模型权重下载入口(默认国内镜像),置空则使用 HuggingFace 官方源",
|
|
135
|
+
)
|
|
136
|
+
MARKER_HF_DISABLE_XET: bool = Field(
|
|
137
|
+
default=True,
|
|
138
|
+
description="禁用 HF Xet 存储后端(国内镜像不支持,开启会导致权重下载挂起)",
|
|
139
|
+
)
|
|
140
|
+
MARKER_LLAMA_CPP_BINARY: str | None = Field(
|
|
141
|
+
default=None,
|
|
142
|
+
description="llama-server 可执行文件路径(None 时沿用系统 LLAMA_CPP_BINARY)",
|
|
143
|
+
)
|
|
144
|
+
|
|
124
145
|
class Config:
|
|
125
146
|
env_file = ".env"
|
|
126
147
|
env_file_encoding = "utf-8"
|