sdpy-kit 0.1.14__tar.gz → 0.2.1__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.14 → sdpy_kit-0.2.1}/PKG-INFO +133 -27
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/README.md +129 -26
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/__init__.py +1 -1
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/config/kit_config.py +21 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/base_db_kit.py +108 -3
- sdpy_kit-0.2.1/kit/db/mysql_kit.py +280 -0
- sdpy_kit-0.2.1/kit/db/pg_kit.py +318 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/sqlite_kit.py +43 -99
- sdpy_kit-0.2.1/kit/marker_kit.py +548 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/pyproject.toml +3 -0
- sdpy_kit-0.1.14/kit/db/mysql_kit.py +0 -89
- sdpy_kit-0.1.14/kit/db/pg_kit.py +0 -87
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/.gitignore +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/__init__.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/base_service.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/chat_service.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/embedding_service.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/exceptions.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/failover.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/image_service.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/model_builder.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/model_client.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/pool.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/profiles.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/rerank_service.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/runner.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/ai/types.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/anydoc_kit.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/common_kit.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/config/__init__.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/config/log_config.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/__init__.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/crud.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/engine.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/exceptions.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/models/__init__.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/models/base.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/query.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/session.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/db/transaction.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/docx_kit.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/file_kit.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/mcp_kit.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/md2doc_kit.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/mineru_kit.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/redis_kit.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/wx_article_kit.py +0 -0
- {sdpy_kit-0.1.14 → sdpy_kit-0.2.1}/kit/zvec_kit.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sdpy-kit
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
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
|
|
|
@@ -81,7 +84,7 @@ SDPY 统一工具集(Kit 体系),供 Python 项目开箱即用:
|
|
|
81
84
|
| 模块 | 类 / 入口 | 能力 | 需要 extra |
|
|
82
85
|
|------|-----------|------|-----------|
|
|
83
86
|
| `kit.config` | `get_settings` / `get_default_logger` | 配置单例与统一日志 | 无 |
|
|
84
|
-
| `kit.db` | `SQLiteKit` / `PgKit` / `MySqlKit` / `CRUDBase` | 统一 CRUD、原生 SQL
|
|
87
|
+
| `kit.db` | `SQLiteKit` / `PgKit` / `MySqlKit` / `CRUDBase` | 统一 CRUD、原生 SQL、原生表操作、事务、表管理 | `pg` / `mysql` / `sqliteai` |
|
|
85
88
|
| `kit.ai` | `AI`(同步门面)/ 4 个原生异步 Service | 对话 / 向量化 / 重排序 / 文生图 | `ai` |
|
|
86
89
|
| `kit.mcp_kit` | `McpKit` | MCP 工具发现与调用 | `mcp` |
|
|
87
90
|
| `kit.redis_kit` | `RedisKit` | Redis string / hash / list / set / zset | `redis` |
|
|
@@ -91,6 +94,7 @@ 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` |
|
|
95
99
|
| `kit.wx_article_kit` | `WxArticleKit` | 微信公众号文章 → Markdown + 图片转存 | 无 |
|
|
96
100
|
|
|
@@ -106,8 +110,8 @@ uv add sdpy-kit
|
|
|
106
110
|
|
|
107
111
|
| extra | 能力 | 安装 |
|
|
108
112
|
|-------|------|------|
|
|
109
|
-
| `pg` | PgKit(PostgreSQL
|
|
110
|
-
| `mysql` | MySqlKit(MySQL
|
|
113
|
+
| `pg` | PgKit(PostgreSQL 驱动;向量方法另需服务端 pgvector) | `pip install "sdpy-kit[pg]"` |
|
|
114
|
+
| `mysql` | MySqlKit(MySQL 驱动;向量仅存储,需 MySQL 9.x) | `pip install "sdpy-kit[mysql]"` |
|
|
111
115
|
| `sqliteai` | SQLiteKit 向量方法(numpy / sqliteai-vector,SQLite 向量扩展) | `pip install "sdpy-kit[sqliteai]"` |
|
|
112
116
|
| `zvec` | ZvecKit(zvec,阿里独立向量库) | `pip install "sdpy-kit[zvec]"` |
|
|
113
117
|
| `redis` | RedisKit | `pip install "sdpy-kit[redis]"` |
|
|
@@ -117,6 +121,7 @@ uv add sdpy-kit
|
|
|
117
121
|
| `anydoc` | AnyDocKit 文档转 Markdown(firecrawl-anydoc + pikepdf) | `pip install "sdpy-kit[anydoc]"` |
|
|
118
122
|
| `docx` | DocxKit 模板动态填充(docxtpl) | `pip install "sdpy-kit[docx]"` |
|
|
119
123
|
| `mineru` | MinerUKit 解析 API(精准解析 + Agent 轻量解析) | `pip install "sdpy-kit[mineru]"` |
|
|
124
|
+
| `marker` | MarkerKit 本地文档解析(marker-pdf[full] → Markdown + Images,依赖体积大) | `pip install "sdpy-kit[marker]"` |
|
|
120
125
|
| `all` | 全部能力 | `pip install "sdpy-kit[all]"` |
|
|
121
126
|
|
|
122
127
|
## 配置(.env)
|
|
@@ -161,6 +166,12 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
161
166
|
|
|
162
167
|
# MinerU(仅精准解析需要 Key,Agent 轻量解析免登录)
|
|
163
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=
|
|
164
175
|
```
|
|
165
176
|
|
|
166
177
|
### 环境变量 ↔ 能力对照表
|
|
@@ -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)` |
|
|
@@ -313,7 +336,7 @@ from kit.db import session_scope, transactional, DBError # 推荐
|
|
|
313
336
|
from kit import session_scope, transactional, DBError # 等价
|
|
314
337
|
```
|
|
315
338
|
|
|
316
|
-
### 1. 三个数据库 Kit(API 完全一致)
|
|
339
|
+
### 1. 三个数据库 Kit(23 个共享方法 API 完全一致)
|
|
317
340
|
|
|
318
341
|
| 类 | 导入 | 数据库 | extra |
|
|
319
342
|
|----|------|--------|-------|
|
|
@@ -321,13 +344,14 @@ from kit import session_scope, transactional, DBError # 等价
|
|
|
321
344
|
| `PgKit` | `from kit.db.pg_kit import PgKit` | PostgreSQL | `pg` |
|
|
322
345
|
| `MySqlKit` | `from kit.db.mysql_kit import MySqlKit` | MySQL | `mysql` |
|
|
323
346
|
|
|
324
|
-
**共有方法(
|
|
347
|
+
**共有方法(23 个,全部为 classmethod,内部自动提交)**
|
|
325
348
|
|
|
326
349
|
| 分组 | 方法 | 说明 |
|
|
327
350
|
|------|------|------|
|
|
328
351
|
| 连接 | `connect() -> bool` | 建引擎并验证连通 |
|
|
329
352
|
| 连接 | `close() -> None` | 关闭引擎 |
|
|
330
353
|
| 连接 | `is_connected() -> bool` | 探测当前是否可连 |
|
|
354
|
+
| 连接 | `raw_connection()` | 取原生 DBAPI 连接(PG=psycopg2 / MySQL=pymysql / SQLite=sqlite3);调用方负责 commit 与 close,psycopg2 / pymysql 默认不自动提交 |
|
|
331
355
|
| ORM | `create(model, data) -> Model` | 插入单条 |
|
|
332
356
|
| ORM | `create_multi(model, data_list) -> list[Model]` | 批量插入 |
|
|
333
357
|
| ORM | `get(model, id) -> Model \| None` | 按主键查询 |
|
|
@@ -339,6 +363,9 @@ from kit import session_scope, transactional, DBError # 等价
|
|
|
339
363
|
| ORM | `count(model) -> int` | 记录总数 |
|
|
340
364
|
| 原生 SQL | `query(sql, params=None) -> list[dict]` | 原生查询,返回字典列表 |
|
|
341
365
|
| 原生 SQL | `execute(sql, params=None) -> int` | 原生写入,返回影响行数 |
|
|
366
|
+
| 原生表 | `create_raw_table(table_name, columns, if_not_exists=True) -> None` | 按「列名 → 列定义」建普通表;⚠ 列定义须按目标库方言书写,不做方言翻译 |
|
|
367
|
+
| 原生表 | `raw_insert(table_name, data) -> int` | 插入一行,返回影响行数 |
|
|
368
|
+
| 原生表 | `raw_get_by(table_name, column, value) -> dict \| None` | 按单列等值取首行 |
|
|
342
369
|
| 事务 | `transaction()` | 事务上下文管理器,`with PgKit.transaction() as session:` |
|
|
343
370
|
| 表 | `list_tables() -> list[str]` | 列出全部表名 |
|
|
344
371
|
| 表 | `table_exists(table_name) -> bool` | 判断表是否存在 |
|
|
@@ -346,11 +373,15 @@ from kit import session_scope, transactional, DBError # 等价
|
|
|
346
373
|
| 表 | `get_table_info(table_name) -> list[dict]` | 获取列信息(三个 Kit 各自实现) |
|
|
347
374
|
|
|
348
375
|
```python
|
|
376
|
+
from sqlalchemy import BigInteger
|
|
349
377
|
from sqlmodel import SQLModel, Field
|
|
378
|
+
from kit.common_kit import CommonKit
|
|
350
379
|
from kit.db.sqlite_kit import SQLiteKit
|
|
351
380
|
|
|
352
381
|
class User(SQLModel, table=True):
|
|
353
|
-
|
|
382
|
+
# 主键:64 位整数 + 雪花 ID(应用侧生成,不用数据库自增)
|
|
383
|
+
id: int = Field(default_factory=CommonKit.generate_snowflake_id,
|
|
384
|
+
primary_key=True, sa_type=BigInteger)
|
|
354
385
|
name: str
|
|
355
386
|
|
|
356
387
|
SQLiteKit.connect()
|
|
@@ -369,31 +400,60 @@ with SQLiteKit.transaction() as session: # 多操作原子提
|
|
|
369
400
|
```
|
|
370
401
|
|
|
371
402
|
> 切换数据库:把 import 的 `SQLiteKit` 换成 `PgKit` / `MySqlKit` 即可,其余代码不变。
|
|
403
|
+
> 注意两点例外:① `create_raw_table` 的列定义文本须按目标库方言改写;② 向量能力
|
|
404
|
+
> **三库同名同参但能力不同**,尤其 **MySQL 侧检索不可用**(见下)。
|
|
372
405
|
|
|
373
|
-
### 2.
|
|
374
|
-
|
|
375
|
-
无需额外依赖:
|
|
406
|
+
### 2. 向量方法(三库同名同参,能力差异化)
|
|
376
407
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
| `raw_insert(table_name, data) -> int` | 插入一行,返回影响行数 |
|
|
382
|
-
| `raw_get_by(table_name, column, value) -> dict \| None` | 按单列等值取首行 |
|
|
383
|
-
|
|
384
|
-
向量方法(需 `pip install "sdpy-kit[sqliteai]"`):
|
|
408
|
+
> 签名在 `SQLiteKit` / `PgKit` / `MySqlKit` 上完全一致;能力按后端不同(见下表)。
|
|
409
|
+
> extra 前提:SQLite 需 `sdpy-kit[sqliteai]`;PG 需 `sdpy-kit[pg]` **且服务端已装 pgvector**
|
|
410
|
+
> (`create_vector_table` 会自动尝试 `CREATE EXTENSION`);MySQL 需 **9.x**(Community 即可存,
|
|
411
|
+
> 但检索需 HeatWave on OCI / MySQL AI)——建表前会校验服务端版本,低于 9.x 抛 `DBError`。
|
|
385
412
|
|
|
386
413
|
| 方法 | 说明 |
|
|
387
414
|
|------|------|
|
|
388
|
-
| `create_vector_table(table_name, id_col="id", dims=384, extra_cols=None) -> None` |
|
|
389
|
-
| `insert_vectors(table_name, vectors, ids=None, extra_data=None) -> int` |
|
|
390
|
-
| `search_vectors(table_name, query_vector, top_k=10, distance_type="COSINE", filter_sql=None) -> list[dict]` | KNN 检索,按距离升序返回 `{"id", "distance"
|
|
391
|
-
| `vector_version() -> str` |
|
|
415
|
+
| `create_vector_table(table_name, id_col="id", dims=384, extra_cols=None) -> None` | 建含向量列的表(PG / MySQL 侧 `dims` 有约束) |
|
|
416
|
+
| `insert_vectors(table_name, vectors, ids=None, extra_data=None) -> int` | 批量插入向量(单事务提交);`ids=None` 时由 Kit 生成雪花 ID |
|
|
417
|
+
| `search_vectors(table_name, query_vector, top_k=10, distance_type="COSINE", filter_sql=None) -> list[dict]` | KNN 检索,按距离升序返回 `{"id", "distance"}`;**MySQL 侧抛 `NotImplementedError`** |
|
|
418
|
+
| `vector_version() -> str` | 向量后端版本;不可用时返回 `"unavailable"`(MySQL 侧为服务端版本号) |
|
|
419
|
+
|
|
420
|
+
**能力差异(跨库不可比较 `distance` 数值)**:
|
|
421
|
+
|
|
422
|
+
| 项 | `SQLiteKit`(sqlite-vector) | `PgKit`(pgvector) | `MySqlKit`(9.x 原生) |
|
|
423
|
+
|----|------------------------------|---------------------|------------------------|
|
|
424
|
+
| 支持的 `distance_type` | **仅 L2**(该形参当前不生效,取任何值结果相同) | `COSINE` / `L2` / `L1` / `DOT`(负内积) / `SQUARED_L2` | **无(检索不可用)** |
|
|
425
|
+
| 非法取值 | 忽略 | 抛 `ValueError` | `search_vectors` 一律抛 `NotImplementedError` |
|
|
426
|
+
| `distance` 口径 | int8 量化整数距离(= L2 × 255,非物理距离) | 真实距离 | — |
|
|
427
|
+
| 维度约束 | 无 | 强制(不匹配即报错) | 上限约束(超限报错) |
|
|
428
|
+
| `filter_sql` 与 `top_k` | **先取 top_k 再过滤**(可能少于 top_k) | **先过滤再取 top_k** | 不适用 |
|
|
429
|
+
| 索引 | 每次检索 `vector_init` + `vector_quantize` | 默认无索引(可自建 hnsw/ivfflat) | 无法建(B-Tree 拒绝向量列) |
|
|
430
|
+
|
|
431
|
+
> MySQL `DISTANCE()` / `VECTOR_DISTANCE()` 仅 HeatWave on OCI 与 MySQL AI 提供
|
|
432
|
+
> (Community 实测报 `1305 FUNCTION ... does not exist`);故 `MySqlKit` 只覆盖存储侧。
|
|
433
|
+
|
|
434
|
+
**主键与 id(三库统一)**:向量表主键均为 `BIGINT`(SQLite 用等价的 64 位 `INTEGER PRIMARY KEY`),
|
|
435
|
+
**不使用数据库自增**;`ids=None` 时由 Kit 用 `CommonKit.generate_snowflake_id()` 生成雪花 ID
|
|
436
|
+
(18~19 位,int64)。
|
|
437
|
+
⚠ 雪花 ID 超过 `2^53`,经 JSON 传给 JavaScript 会丢精度,需按字符串传输;
|
|
438
|
+
多实例部署需各自 `CommonKit.configure(datacenter_id, machine_id)`(默认 `(1,1)` 会重复)。
|
|
392
439
|
|
|
393
440
|
```python
|
|
441
|
+
# SQLite
|
|
442
|
+
from kit.db.sqlite_kit import SQLiteKit
|
|
394
443
|
SQLiteKit.create_vector_table("images", dims=384)
|
|
395
444
|
SQLiteKit.insert_vectors("images", [[0.1] * 384, [0.2] * 384])
|
|
396
445
|
rows = SQLiteKit.search_vectors("images", [0.1] * 384, top_k=5)
|
|
446
|
+
|
|
447
|
+
# PostgreSQL(签名相同;可选 COSINE/L2/L1/DOT/SQUARED_L2)
|
|
448
|
+
from kit.db.pg_kit import PgKit
|
|
449
|
+
PgKit.create_vector_table("images", dims=384)
|
|
450
|
+
PgKit.insert_vectors("images", [[0.1] * 384, [0.2] * 384])
|
|
451
|
+
rows = PgKit.search_vectors("images", [0.1] * 384, top_k=5, distance_type="L2")
|
|
452
|
+
|
|
453
|
+
# MySQL(仅存储;search_vectors 会抛 NotImplementedError)
|
|
454
|
+
from kit.db.mysql_kit import MySqlKit
|
|
455
|
+
MySqlKit.create_vector_table("images", dims=384)
|
|
456
|
+
MySqlKit.insert_vectors("images", [[0.1] * 384, [0.2] * 384])
|
|
397
457
|
```
|
|
398
458
|
|
|
399
459
|
### 3. CRUDBase(配合 session_scope,不自动提交)
|
|
@@ -458,10 +518,16 @@ def transfer(session: Session, from_id: int, to_id: int, amount: float) -> None:
|
|
|
458
518
|
### 5. 模型混入类与查询构建器
|
|
459
519
|
|
|
460
520
|
```python
|
|
521
|
+
from sqlalchemy import BigInteger
|
|
522
|
+
from sqlmodel import Field, SQLModel
|
|
523
|
+
|
|
524
|
+
from kit.common_kit import CommonKit
|
|
461
525
|
from kit.db.models import TimestampMixin, SoftDeleteMixin, AuditMixin
|
|
462
526
|
|
|
463
|
-
class Article(TimestampMixin, SoftDeleteMixin, table=True):
|
|
464
|
-
|
|
527
|
+
class Article(TimestampMixin, SoftDeleteMixin, SQLModel, table=True):
|
|
528
|
+
# 主键:64 位整数 + 雪花 ID(应用侧生成,不用数据库自增)
|
|
529
|
+
id: int = Field(default_factory=CommonKit.generate_snowflake_id,
|
|
530
|
+
primary_key=True, sa_type=BigInteger)
|
|
465
531
|
title: str
|
|
466
532
|
```
|
|
467
533
|
|
|
@@ -810,6 +876,46 @@ if r.state == "done":
|
|
|
810
876
|
|
|
811
877
|
---
|
|
812
878
|
|
|
879
|
+
## kit.marker_kit —— 本地文档解析(Markdown + Images)
|
|
880
|
+
|
|
881
|
+
安装:`pip install "sdpy-kit[marker]"`(依赖 `marker-pdf[full]`,含 torch 等 80+ 包,体积较大)
|
|
882
|
+
|
|
883
|
+
```python
|
|
884
|
+
from kit.marker_kit import MarkerKit
|
|
885
|
+
|
|
886
|
+
# 落盘 md + images(推荐):源文件同目录下建同名子目录
|
|
887
|
+
md_path = MarkerKit.convert_to_dir("report.pdf") # -> report/report.md + 图片
|
|
888
|
+
md_path = MarkerKit.convert_to_dir("report.pdf", "out/doc") # 指定产物目录
|
|
889
|
+
|
|
890
|
+
# 只取 Markdown 文本(图片不落盘)
|
|
891
|
+
md = MarkerKit.convert_to_md("report.pdf")
|
|
892
|
+
|
|
893
|
+
# 安全转换(不抛异常,返回结果对象)
|
|
894
|
+
result = MarkerKit.convert("report.pdf", "out/doc")
|
|
895
|
+
if result.success:
|
|
896
|
+
print(result.md_path, len(result.image_paths), result.page_count)
|
|
897
|
+
|
|
898
|
+
# 跳过 VLM(无需 llama.cpp)
|
|
899
|
+
md = MarkerKit.convert_to_md("scan.pdf", disable_ocr=True)
|
|
900
|
+
|
|
901
|
+
MarkerKit.shutdown() # 释放模型与推理服务(幂等)
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
| 方法 | 说明 |
|
|
905
|
+
|------|------|
|
|
906
|
+
| `is_supported(file_path) -> bool` | 扩展名白名单(pdf / 图片 / docx / pptx / xlsx / html / epub) |
|
|
907
|
+
| `convert_to_md(file_path, *, mode=None, force_ocr=None, disable_ocr=None, page_range=None) -> str` | 解析并返回 Markdown 文本(图片不落盘) |
|
|
908
|
+
| `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 绝对路径 |
|
|
909
|
+
| `convert(src_path, output_dir=None, *, ...) -> MarkerResult` | 安全版:失败封装为 `MarkerResult`,不抛异常 |
|
|
910
|
+
| `shutdown() -> None` | 释放模型与共享推理服务(幂等) |
|
|
911
|
+
|
|
912
|
+
> 产物:`<output_dir>/<源文件名>.md` + 图片文件(md 内相对路径引用),**不生成** `_meta.json`。
|
|
913
|
+
> 结果类型:`MarkerResult`(`success` / `markdown` / `file_path` / `output_dir` / `md_path` / `image_paths` / `page_count` / `error`);异常:`MarkerError`。
|
|
914
|
+
> `mode` 缺省时不写入配置,交由 marker 按设备自动选择;首次使用会下载模型权重(默认走 `MARKER_HF_ENDPOINT` 镜像)。
|
|
915
|
+
> 非 NVIDIA 平台完整 VLM 能力(公式 / 扫描页 OCR)需 llama.cpp 的 `llama-server`,否则用 `disable_ocr=True` 跳过。
|
|
916
|
+
|
|
917
|
+
---
|
|
918
|
+
|
|
813
919
|
## kit.zvec_kit —— 本地向量库
|
|
814
920
|
|
|
815
921
|
安装:`pip install "sdpy-kit[zvec]"`
|
|
@@ -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
|
|
|
@@ -14,7 +14,7 @@ SDPY 统一工具集(Kit 体系),供 Python 项目开箱即用:
|
|
|
14
14
|
| 模块 | 类 / 入口 | 能力 | 需要 extra |
|
|
15
15
|
|------|-----------|------|-----------|
|
|
16
16
|
| `kit.config` | `get_settings` / `get_default_logger` | 配置单例与统一日志 | 无 |
|
|
17
|
-
| `kit.db` | `SQLiteKit` / `PgKit` / `MySqlKit` / `CRUDBase` | 统一 CRUD、原生 SQL
|
|
17
|
+
| `kit.db` | `SQLiteKit` / `PgKit` / `MySqlKit` / `CRUDBase` | 统一 CRUD、原生 SQL、原生表操作、事务、表管理 | `pg` / `mysql` / `sqliteai` |
|
|
18
18
|
| `kit.ai` | `AI`(同步门面)/ 4 个原生异步 Service | 对话 / 向量化 / 重排序 / 文生图 | `ai` |
|
|
19
19
|
| `kit.mcp_kit` | `McpKit` | MCP 工具发现与调用 | `mcp` |
|
|
20
20
|
| `kit.redis_kit` | `RedisKit` | Redis string / hash / list / set / zset | `redis` |
|
|
@@ -24,6 +24,7 @@ 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` |
|
|
28
29
|
| `kit.wx_article_kit` | `WxArticleKit` | 微信公众号文章 → Markdown + 图片转存 | 无 |
|
|
29
30
|
|
|
@@ -39,8 +40,8 @@ uv add sdpy-kit
|
|
|
39
40
|
|
|
40
41
|
| extra | 能力 | 安装 |
|
|
41
42
|
|-------|------|------|
|
|
42
|
-
| `pg` | PgKit(PostgreSQL
|
|
43
|
-
| `mysql` | MySqlKit(MySQL
|
|
43
|
+
| `pg` | PgKit(PostgreSQL 驱动;向量方法另需服务端 pgvector) | `pip install "sdpy-kit[pg]"` |
|
|
44
|
+
| `mysql` | MySqlKit(MySQL 驱动;向量仅存储,需 MySQL 9.x) | `pip install "sdpy-kit[mysql]"` |
|
|
44
45
|
| `sqliteai` | SQLiteKit 向量方法(numpy / sqliteai-vector,SQLite 向量扩展) | `pip install "sdpy-kit[sqliteai]"` |
|
|
45
46
|
| `zvec` | ZvecKit(zvec,阿里独立向量库) | `pip install "sdpy-kit[zvec]"` |
|
|
46
47
|
| `redis` | RedisKit | `pip install "sdpy-kit[redis]"` |
|
|
@@ -50,6 +51,7 @@ uv add sdpy-kit
|
|
|
50
51
|
| `anydoc` | AnyDocKit 文档转 Markdown(firecrawl-anydoc + pikepdf) | `pip install "sdpy-kit[anydoc]"` |
|
|
51
52
|
| `docx` | DocxKit 模板动态填充(docxtpl) | `pip install "sdpy-kit[docx]"` |
|
|
52
53
|
| `mineru` | MinerUKit 解析 API(精准解析 + Agent 轻量解析) | `pip install "sdpy-kit[mineru]"` |
|
|
54
|
+
| `marker` | MarkerKit 本地文档解析(marker-pdf[full] → Markdown + Images,依赖体积大) | `pip install "sdpy-kit[marker]"` |
|
|
53
55
|
| `all` | 全部能力 | `pip install "sdpy-kit[all]"` |
|
|
54
56
|
|
|
55
57
|
## 配置(.env)
|
|
@@ -94,6 +96,12 @@ SQLITE_DB_PATH=./data/sqlite.db
|
|
|
94
96
|
|
|
95
97
|
# MinerU(仅精准解析需要 Key,Agent 轻量解析免登录)
|
|
96
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=
|
|
97
105
|
```
|
|
98
106
|
|
|
99
107
|
### 环境变量 ↔ 能力对照表
|
|
@@ -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)` |
|
|
@@ -246,7 +266,7 @@ from kit.db import session_scope, transactional, DBError # 推荐
|
|
|
246
266
|
from kit import session_scope, transactional, DBError # 等价
|
|
247
267
|
```
|
|
248
268
|
|
|
249
|
-
### 1. 三个数据库 Kit(API 完全一致)
|
|
269
|
+
### 1. 三个数据库 Kit(23 个共享方法 API 完全一致)
|
|
250
270
|
|
|
251
271
|
| 类 | 导入 | 数据库 | extra |
|
|
252
272
|
|----|------|--------|-------|
|
|
@@ -254,13 +274,14 @@ from kit import session_scope, transactional, DBError # 等价
|
|
|
254
274
|
| `PgKit` | `from kit.db.pg_kit import PgKit` | PostgreSQL | `pg` |
|
|
255
275
|
| `MySqlKit` | `from kit.db.mysql_kit import MySqlKit` | MySQL | `mysql` |
|
|
256
276
|
|
|
257
|
-
**共有方法(
|
|
277
|
+
**共有方法(23 个,全部为 classmethod,内部自动提交)**
|
|
258
278
|
|
|
259
279
|
| 分组 | 方法 | 说明 |
|
|
260
280
|
|------|------|------|
|
|
261
281
|
| 连接 | `connect() -> bool` | 建引擎并验证连通 |
|
|
262
282
|
| 连接 | `close() -> None` | 关闭引擎 |
|
|
263
283
|
| 连接 | `is_connected() -> bool` | 探测当前是否可连 |
|
|
284
|
+
| 连接 | `raw_connection()` | 取原生 DBAPI 连接(PG=psycopg2 / MySQL=pymysql / SQLite=sqlite3);调用方负责 commit 与 close,psycopg2 / pymysql 默认不自动提交 |
|
|
264
285
|
| ORM | `create(model, data) -> Model` | 插入单条 |
|
|
265
286
|
| ORM | `create_multi(model, data_list) -> list[Model]` | 批量插入 |
|
|
266
287
|
| ORM | `get(model, id) -> Model \| None` | 按主键查询 |
|
|
@@ -272,6 +293,9 @@ from kit import session_scope, transactional, DBError # 等价
|
|
|
272
293
|
| ORM | `count(model) -> int` | 记录总数 |
|
|
273
294
|
| 原生 SQL | `query(sql, params=None) -> list[dict]` | 原生查询,返回字典列表 |
|
|
274
295
|
| 原生 SQL | `execute(sql, params=None) -> int` | 原生写入,返回影响行数 |
|
|
296
|
+
| 原生表 | `create_raw_table(table_name, columns, if_not_exists=True) -> None` | 按「列名 → 列定义」建普通表;⚠ 列定义须按目标库方言书写,不做方言翻译 |
|
|
297
|
+
| 原生表 | `raw_insert(table_name, data) -> int` | 插入一行,返回影响行数 |
|
|
298
|
+
| 原生表 | `raw_get_by(table_name, column, value) -> dict \| None` | 按单列等值取首行 |
|
|
275
299
|
| 事务 | `transaction()` | 事务上下文管理器,`with PgKit.transaction() as session:` |
|
|
276
300
|
| 表 | `list_tables() -> list[str]` | 列出全部表名 |
|
|
277
301
|
| 表 | `table_exists(table_name) -> bool` | 判断表是否存在 |
|
|
@@ -279,11 +303,15 @@ from kit import session_scope, transactional, DBError # 等价
|
|
|
279
303
|
| 表 | `get_table_info(table_name) -> list[dict]` | 获取列信息(三个 Kit 各自实现) |
|
|
280
304
|
|
|
281
305
|
```python
|
|
306
|
+
from sqlalchemy import BigInteger
|
|
282
307
|
from sqlmodel import SQLModel, Field
|
|
308
|
+
from kit.common_kit import CommonKit
|
|
283
309
|
from kit.db.sqlite_kit import SQLiteKit
|
|
284
310
|
|
|
285
311
|
class User(SQLModel, table=True):
|
|
286
|
-
|
|
312
|
+
# 主键:64 位整数 + 雪花 ID(应用侧生成,不用数据库自增)
|
|
313
|
+
id: int = Field(default_factory=CommonKit.generate_snowflake_id,
|
|
314
|
+
primary_key=True, sa_type=BigInteger)
|
|
287
315
|
name: str
|
|
288
316
|
|
|
289
317
|
SQLiteKit.connect()
|
|
@@ -302,31 +330,60 @@ with SQLiteKit.transaction() as session: # 多操作原子提
|
|
|
302
330
|
```
|
|
303
331
|
|
|
304
332
|
> 切换数据库:把 import 的 `SQLiteKit` 换成 `PgKit` / `MySqlKit` 即可,其余代码不变。
|
|
333
|
+
> 注意两点例外:① `create_raw_table` 的列定义文本须按目标库方言改写;② 向量能力
|
|
334
|
+
> **三库同名同参但能力不同**,尤其 **MySQL 侧检索不可用**(见下)。
|
|
305
335
|
|
|
306
|
-
### 2.
|
|
307
|
-
|
|
308
|
-
无需额外依赖:
|
|
336
|
+
### 2. 向量方法(三库同名同参,能力差异化)
|
|
309
337
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
| `raw_insert(table_name, data) -> int` | 插入一行,返回影响行数 |
|
|
315
|
-
| `raw_get_by(table_name, column, value) -> dict \| None` | 按单列等值取首行 |
|
|
316
|
-
|
|
317
|
-
向量方法(需 `pip install "sdpy-kit[sqliteai]"`):
|
|
338
|
+
> 签名在 `SQLiteKit` / `PgKit` / `MySqlKit` 上完全一致;能力按后端不同(见下表)。
|
|
339
|
+
> extra 前提:SQLite 需 `sdpy-kit[sqliteai]`;PG 需 `sdpy-kit[pg]` **且服务端已装 pgvector**
|
|
340
|
+
> (`create_vector_table` 会自动尝试 `CREATE EXTENSION`);MySQL 需 **9.x**(Community 即可存,
|
|
341
|
+
> 但检索需 HeatWave on OCI / MySQL AI)——建表前会校验服务端版本,低于 9.x 抛 `DBError`。
|
|
318
342
|
|
|
319
343
|
| 方法 | 说明 |
|
|
320
344
|
|------|------|
|
|
321
|
-
| `create_vector_table(table_name, id_col="id", dims=384, extra_cols=None) -> None` |
|
|
322
|
-
| `insert_vectors(table_name, vectors, ids=None, extra_data=None) -> int` |
|
|
323
|
-
| `search_vectors(table_name, query_vector, top_k=10, distance_type="COSINE", filter_sql=None) -> list[dict]` | KNN 检索,按距离升序返回 `{"id", "distance"
|
|
324
|
-
| `vector_version() -> str` |
|
|
345
|
+
| `create_vector_table(table_name, id_col="id", dims=384, extra_cols=None) -> None` | 建含向量列的表(PG / MySQL 侧 `dims` 有约束) |
|
|
346
|
+
| `insert_vectors(table_name, vectors, ids=None, extra_data=None) -> int` | 批量插入向量(单事务提交);`ids=None` 时由 Kit 生成雪花 ID |
|
|
347
|
+
| `search_vectors(table_name, query_vector, top_k=10, distance_type="COSINE", filter_sql=None) -> list[dict]` | KNN 检索,按距离升序返回 `{"id", "distance"}`;**MySQL 侧抛 `NotImplementedError`** |
|
|
348
|
+
| `vector_version() -> str` | 向量后端版本;不可用时返回 `"unavailable"`(MySQL 侧为服务端版本号) |
|
|
349
|
+
|
|
350
|
+
**能力差异(跨库不可比较 `distance` 数值)**:
|
|
351
|
+
|
|
352
|
+
| 项 | `SQLiteKit`(sqlite-vector) | `PgKit`(pgvector) | `MySqlKit`(9.x 原生) |
|
|
353
|
+
|----|------------------------------|---------------------|------------------------|
|
|
354
|
+
| 支持的 `distance_type` | **仅 L2**(该形参当前不生效,取任何值结果相同) | `COSINE` / `L2` / `L1` / `DOT`(负内积) / `SQUARED_L2` | **无(检索不可用)** |
|
|
355
|
+
| 非法取值 | 忽略 | 抛 `ValueError` | `search_vectors` 一律抛 `NotImplementedError` |
|
|
356
|
+
| `distance` 口径 | int8 量化整数距离(= L2 × 255,非物理距离) | 真实距离 | — |
|
|
357
|
+
| 维度约束 | 无 | 强制(不匹配即报错) | 上限约束(超限报错) |
|
|
358
|
+
| `filter_sql` 与 `top_k` | **先取 top_k 再过滤**(可能少于 top_k) | **先过滤再取 top_k** | 不适用 |
|
|
359
|
+
| 索引 | 每次检索 `vector_init` + `vector_quantize` | 默认无索引(可自建 hnsw/ivfflat) | 无法建(B-Tree 拒绝向量列) |
|
|
360
|
+
|
|
361
|
+
> MySQL `DISTANCE()` / `VECTOR_DISTANCE()` 仅 HeatWave on OCI 与 MySQL AI 提供
|
|
362
|
+
> (Community 实测报 `1305 FUNCTION ... does not exist`);故 `MySqlKit` 只覆盖存储侧。
|
|
363
|
+
|
|
364
|
+
**主键与 id(三库统一)**:向量表主键均为 `BIGINT`(SQLite 用等价的 64 位 `INTEGER PRIMARY KEY`),
|
|
365
|
+
**不使用数据库自增**;`ids=None` 时由 Kit 用 `CommonKit.generate_snowflake_id()` 生成雪花 ID
|
|
366
|
+
(18~19 位,int64)。
|
|
367
|
+
⚠ 雪花 ID 超过 `2^53`,经 JSON 传给 JavaScript 会丢精度,需按字符串传输;
|
|
368
|
+
多实例部署需各自 `CommonKit.configure(datacenter_id, machine_id)`(默认 `(1,1)` 会重复)。
|
|
325
369
|
|
|
326
370
|
```python
|
|
371
|
+
# SQLite
|
|
372
|
+
from kit.db.sqlite_kit import SQLiteKit
|
|
327
373
|
SQLiteKit.create_vector_table("images", dims=384)
|
|
328
374
|
SQLiteKit.insert_vectors("images", [[0.1] * 384, [0.2] * 384])
|
|
329
375
|
rows = SQLiteKit.search_vectors("images", [0.1] * 384, top_k=5)
|
|
376
|
+
|
|
377
|
+
# PostgreSQL(签名相同;可选 COSINE/L2/L1/DOT/SQUARED_L2)
|
|
378
|
+
from kit.db.pg_kit import PgKit
|
|
379
|
+
PgKit.create_vector_table("images", dims=384)
|
|
380
|
+
PgKit.insert_vectors("images", [[0.1] * 384, [0.2] * 384])
|
|
381
|
+
rows = PgKit.search_vectors("images", [0.1] * 384, top_k=5, distance_type="L2")
|
|
382
|
+
|
|
383
|
+
# MySQL(仅存储;search_vectors 会抛 NotImplementedError)
|
|
384
|
+
from kit.db.mysql_kit import MySqlKit
|
|
385
|
+
MySqlKit.create_vector_table("images", dims=384)
|
|
386
|
+
MySqlKit.insert_vectors("images", [[0.1] * 384, [0.2] * 384])
|
|
330
387
|
```
|
|
331
388
|
|
|
332
389
|
### 3. CRUDBase(配合 session_scope,不自动提交)
|
|
@@ -391,10 +448,16 @@ def transfer(session: Session, from_id: int, to_id: int, amount: float) -> None:
|
|
|
391
448
|
### 5. 模型混入类与查询构建器
|
|
392
449
|
|
|
393
450
|
```python
|
|
451
|
+
from sqlalchemy import BigInteger
|
|
452
|
+
from sqlmodel import Field, SQLModel
|
|
453
|
+
|
|
454
|
+
from kit.common_kit import CommonKit
|
|
394
455
|
from kit.db.models import TimestampMixin, SoftDeleteMixin, AuditMixin
|
|
395
456
|
|
|
396
|
-
class Article(TimestampMixin, SoftDeleteMixin, table=True):
|
|
397
|
-
|
|
457
|
+
class Article(TimestampMixin, SoftDeleteMixin, SQLModel, table=True):
|
|
458
|
+
# 主键:64 位整数 + 雪花 ID(应用侧生成,不用数据库自增)
|
|
459
|
+
id: int = Field(default_factory=CommonKit.generate_snowflake_id,
|
|
460
|
+
primary_key=True, sa_type=BigInteger)
|
|
398
461
|
title: str
|
|
399
462
|
```
|
|
400
463
|
|
|
@@ -743,6 +806,46 @@ if r.state == "done":
|
|
|
743
806
|
|
|
744
807
|
---
|
|
745
808
|
|
|
809
|
+
## kit.marker_kit —— 本地文档解析(Markdown + Images)
|
|
810
|
+
|
|
811
|
+
安装:`pip install "sdpy-kit[marker]"`(依赖 `marker-pdf[full]`,含 torch 等 80+ 包,体积较大)
|
|
812
|
+
|
|
813
|
+
```python
|
|
814
|
+
from kit.marker_kit import MarkerKit
|
|
815
|
+
|
|
816
|
+
# 落盘 md + images(推荐):源文件同目录下建同名子目录
|
|
817
|
+
md_path = MarkerKit.convert_to_dir("report.pdf") # -> report/report.md + 图片
|
|
818
|
+
md_path = MarkerKit.convert_to_dir("report.pdf", "out/doc") # 指定产物目录
|
|
819
|
+
|
|
820
|
+
# 只取 Markdown 文本(图片不落盘)
|
|
821
|
+
md = MarkerKit.convert_to_md("report.pdf")
|
|
822
|
+
|
|
823
|
+
# 安全转换(不抛异常,返回结果对象)
|
|
824
|
+
result = MarkerKit.convert("report.pdf", "out/doc")
|
|
825
|
+
if result.success:
|
|
826
|
+
print(result.md_path, len(result.image_paths), result.page_count)
|
|
827
|
+
|
|
828
|
+
# 跳过 VLM(无需 llama.cpp)
|
|
829
|
+
md = MarkerKit.convert_to_md("scan.pdf", disable_ocr=True)
|
|
830
|
+
|
|
831
|
+
MarkerKit.shutdown() # 释放模型与推理服务(幂等)
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
| 方法 | 说明 |
|
|
835
|
+
|------|------|
|
|
836
|
+
| `is_supported(file_path) -> bool` | 扩展名白名单(pdf / 图片 / docx / pptx / xlsx / html / epub) |
|
|
837
|
+
| `convert_to_md(file_path, *, mode=None, force_ocr=None, disable_ocr=None, page_range=None) -> str` | 解析并返回 Markdown 文本(图片不落盘) |
|
|
838
|
+
| `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 绝对路径 |
|
|
839
|
+
| `convert(src_path, output_dir=None, *, ...) -> MarkerResult` | 安全版:失败封装为 `MarkerResult`,不抛异常 |
|
|
840
|
+
| `shutdown() -> None` | 释放模型与共享推理服务(幂等) |
|
|
841
|
+
|
|
842
|
+
> 产物:`<output_dir>/<源文件名>.md` + 图片文件(md 内相对路径引用),**不生成** `_meta.json`。
|
|
843
|
+
> 结果类型:`MarkerResult`(`success` / `markdown` / `file_path` / `output_dir` / `md_path` / `image_paths` / `page_count` / `error`);异常:`MarkerError`。
|
|
844
|
+
> `mode` 缺省时不写入配置,交由 marker 按设备自动选择;首次使用会下载模型权重(默认走 `MARKER_HF_ENDPOINT` 镜像)。
|
|
845
|
+
> 非 NVIDIA 平台完整 VLM 能力(公式 / 扫描页 OCR)需 llama.cpp 的 `llama-server`,否则用 `disable_ocr=True` 跳过。
|
|
846
|
+
|
|
847
|
+
---
|
|
848
|
+
|
|
746
849
|
## kit.zvec_kit —— 本地向量库
|
|
747
850
|
|
|
748
851
|
安装:`pip install "sdpy-kit[zvec]"`
|
|
@@ -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"
|