sdpy-kit 0.2.2__tar.gz → 0.2.4__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.
Files changed (46) hide show
  1. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/PKG-INFO +82 -6
  2. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/README.md +81 -5
  3. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/__init__.py +25 -1
  4. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/__init__.py +23 -0
  5. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/base_db_kit.py +228 -9
  6. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/mysql_kit.py +31 -63
  7. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/pg_kit.py +45 -58
  8. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/sqlite_kit.py +87 -61
  9. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/.gitignore +0 -0
  10. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/__init__.py +0 -0
  11. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/base_service.py +0 -0
  12. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/chat_service.py +0 -0
  13. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/embedding_service.py +0 -0
  14. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/exceptions.py +0 -0
  15. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/failover.py +0 -0
  16. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/image_service.py +0 -0
  17. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/model_builder.py +0 -0
  18. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/model_client.py +0 -0
  19. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/pool.py +0 -0
  20. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/profiles.py +0 -0
  21. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/rerank_service.py +0 -0
  22. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/runner.py +0 -0
  23. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/ai/types.py +0 -0
  24. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/anydoc_kit.py +0 -0
  25. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/common_kit.py +0 -0
  26. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/config/__init__.py +0 -0
  27. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/config/kit_config.py +0 -0
  28. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/config/log_config.py +0 -0
  29. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/crud.py +0 -0
  30. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/engine.py +0 -0
  31. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/exceptions.py +0 -0
  32. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/models/__init__.py +0 -0
  33. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/models/base.py +0 -0
  34. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/query.py +0 -0
  35. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/session.py +0 -0
  36. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/db/transaction.py +0 -0
  37. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/docx_kit.py +0 -0
  38. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/file_kit.py +0 -0
  39. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/marker_kit.py +0 -0
  40. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/mcp_kit.py +0 -0
  41. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/md2doc_kit.py +0 -0
  42. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/mineru_kit.py +0 -0
  43. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/redis_kit.py +0 -0
  44. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/wx_article_kit.py +0 -0
  45. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/kit/zvec_kit.py +0 -0
  46. {sdpy_kit-0.2.2 → sdpy_kit-0.2.4}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sdpy-kit
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: SDPY Kit——统一数据库访问层(PG/MySQL/SQLite)与 AI/MCP/Redis/文件/文档/向量工具集
5
5
  Author-email: Clark <changhongyuan@126.com>
6
6
  License-Expression: MIT
@@ -336,7 +336,7 @@ from kit.db import session_scope, transactional, DBError # 推荐
336
336
  from kit import session_scope, transactional, DBError # 等价
337
337
  ```
338
338
 
339
- ### 1. 三个数据库 Kit(23 个共享方法 API 完全一致)
339
+ ### 1. 三个数据库 Kit(24 个共享方法 API 完全一致)
340
340
 
341
341
  | 类 | 导入 | 数据库 | extra |
342
342
  |----|------|--------|-------|
@@ -370,13 +370,23 @@ from kit import session_scope, transactional, DBError # 等价
370
370
  | 表 | `list_tables() -> list[str]` | 列出全部表名 |
371
371
  | 表 | `table_exists(table_name) -> bool` | 判断表是否存在 |
372
372
  | 表 | `create_tables(models) -> None` | 按模型列表建表 |
373
- | 表 | `get_table_info(table_name) -> list[dict]` | 获取列信息(三个 Kit 各自实现) |
373
+ | 表 | `get_table_info(table_name) -> list[dict]` | 获取列信息(按列序;公共键 4 个:`column_name`/`data_type`/`is_nullable`/`column_default`) |
374
+
375
+ > **列表参数(`IN`)**:`query` / `execute` 的 `params` 中值为 `list`/`tuple`/`set`/`frozenset`
376
+ > 时按 `IN` 展开,可直接写 `WHERE id IN :ids`(三库通用)。`IN` **不保证顺序**;参数列表过大
377
+ > 应分批(PG 单语句上限 65535 参数)。
378
+ >
379
+ > **`LIKE` 的方言差异**:SQLite 对 ASCII 不区分大小写,PostgreSQL 区分(用 `ILIKE`);
380
+ > 跨库一致写法:`LOWER(col) LIKE LOWER(:pattern)`。
381
+ >
382
+ > **导出面**:`from kit.db import PgKit, SQLiteKit, build_pg_url, to_vector_literal, …`
383
+ > (`kit` 顶层与 `kit.db` 导出同一套符号)。
374
384
 
375
385
  ```python
376
386
  from sqlalchemy import BigInteger
377
387
  from sqlmodel import SQLModel, Field
378
388
  from kit.common_kit import CommonKit
379
- from kit.db.sqlite_kit import SQLiteKit
389
+ from kit.db import SQLiteKit # 也可 from kit.db.sqlite_kit import SQLiteKit
380
390
 
381
391
  class User(SQLModel, table=True):
382
392
  # 主键:64 位整数 + 雪花 ID(应用侧生成,不用数据库自增)
@@ -393,6 +403,7 @@ users = SQLiteKit.list(User, skip=0, limit=10, order_by="id", desc=True)
393
403
 
394
404
  rows = SQLiteKit.query("SELECT * FROM user WHERE name = :name", {"name": "李四"})
395
405
  affected = SQLiteKit.execute("UPDATE user SET name = '王五' WHERE id = :id", {"id": user.id})
406
+ rows = SQLiteKit.query("SELECT * FROM user WHERE id IN :ids", {"ids": [1, 2, 3]}) # 列表参数
396
407
 
397
408
  with SQLiteKit.transaction() as session: # 多操作原子提交
398
409
  SQLiteKit.create(User, {"name": "批量一"})
@@ -413,8 +424,9 @@ with SQLiteKit.transaction() as session: # 多操作原子提
413
424
 
414
425
  | 方法 | 说明 |
415
426
  |------|------|
416
- | `create_vector_table(table_name, dims, id_col="id", column="embedding", extra_cols=None) -> None` | 建含向量列的表;**`dims` 必填**(SQLite 用 `CHECK` 落实为数据库层约束;PG 硬约束并回读校验已存在表;MySQL 为上限语义) |
417
- | `insert_vectors(table_name, vectors, ids=None, extra_data=None, id_col="id", column="embedding") -> int` | 批量插入向量(单事务提交);`ids=None` 时由 Kit 生成雪花 ID;接受 `list[list[float]]` 或二维 numpy 数组 |
427
+ | `create_vector_table(table_name, dims, id_col="id", column="embedding", extra_cols=None) -> None` | 建含向量列的表;**`dims` 必填**(SQLite 用 `CHECK` 落实为数据库层约束;PG 硬约束并回读校验已存在表;MySQL 为上限语义)。`extra_cols` 支持 `{列名: 类型串}`(推荐,与 `create_raw_table` 同形)与 `[{"name","type"}]` 两种形态 |
428
+ | `insert_vectors(table_name, vectors, ids=None, extra_data=None, id_col="id", column="embedding") -> int` | 批量插入向量(**自成一事务并提交**);`ids=None` 时由 Kit 生成雪花 ID;接受 `list[list[float]]` 或二维 numpy 数组 |
429
+ | `build_insert_vectors(table_name, vectors, ids=None, extra_data=None, id_col="id", column="embedding") -> list[tuple[str, list[dict]]]` | **只拼装、不执行、不管事务**:返回按列集分组的 `(SQL, 参数列表)`,供调用方在**自有事务**内写向量行(见「自有事务内写向量」) |
418
430
  | `search_vectors(table_name, query_vector, top_k=10, distance_type="L2", filter_sql=None, exact=True, id_col="id", column="embedding") -> list[dict]` | KNN 检索,按距离升序返回 `{"id", "distance"}`;`exact=True`(默认)禁止近似加速;**MySQL 侧抛 `VectorNotSupportedError`** |
419
431
  | `vector_version() -> str` | 向量后端版本;不可用时返回 `"unavailable"`(MySQL 侧为服务端版本号) |
420
432
 
@@ -499,6 +511,70 @@ PgKit.search_vectors("my_vec", [0.1] * 384, top_k=5, id_col="vid", column="vec")
499
511
  > 新增(非破坏性):`VECTOR_CAPABILITIES` 能力声明、`id_col` / `column` 逃生口参数、
500
512
  > `insert_vectors` 支持二维 numpy 数组与批量提交。
501
513
 
514
+ #### 0.2.4 变更
515
+
516
+ | 编号 | 变更 | 影响 |
517
+ |------|------|------|
518
+ | B4 | **入参自洽性校验**(`extra_data` 的键):保留绑定名 `id` / `vec`、与 `id_col` / `column` 重复、不是合法标识符、`id_col == column` → 抛可操作的 `ValueError` | **唯一行为变更**:此前 SQLite 会**静默写坏数据**(如 `id` 列被覆盖)、PG/MySQL 报误导性错误;正常调用**零影响** |
519
+ | — | 新增共享方法 `build_insert_vectors`(只拼装不执行,由 `BaseDbKit` 收敛 → 共享方法 23 → **24**) | 纯新增:可在**自有事务**内写向量行(见下) |
520
+ | — | `create_vector_table` 的 `extra_cols` 支持 `{列名: 类型串}`(与 `create_raw_table` 同形) | 纯新增:既有 `[{"name","type"}]` 形态保留,两者产出 DDL 逐字一致 |
521
+ | — | 后端差异收口:向量列占位符由 `VECTOR_PLACEHOLDER` 驱动(MySQL = `STRING_TO_VECTOR(:vec)`) | 内部整理:公开签名与行为不变 |
522
+ | — | `SQLiteKit.insert_vectors` 的事务获取统一为 `transaction()`(与另两库同构) | 内部一致:行为等价(自成一事务并提交) |
523
+
524
+ #### 0.2.3 变更
525
+
526
+ | 编号 | 变更 | 影响 |
527
+ |------|------|------|
528
+ | B6 | **`PgKit.get_table_info` 按数据库解析语义定位表**(`search_path` 解析到的那张表) | 多 schema 下同名表**不再混行**;单 schema / `public` 场景**无影响**;只接受非限定表名 |
529
+ | — | `query` / `execute` 支持**列表参数**(`IN :ids`,三库通用) | 纯新增;`set`/`frozenset` 自动归一化为 `list` |
530
+ | — | 新增 `SQLiteKit.encode_vector` / `decode_vector`(小端 float32) | 纯新增:可在自有事务内写向量表,见下 |
531
+ | — | 导出面统一:`from kit.db import PgKit, MySqlKit, SQLiteKit, build_pg_url, …` | 纯新增;既有导出未删除/未改名 |
532
+
533
+ **两段查询范式(推荐用法)**:`search_vectors` 只返回 `[{"id", "distance"}]`,载荷二次取回:
534
+
535
+ ```python
536
+ hits = SQLiteKit.search_vectors("item_vectors", query_vector, top_k=5)
537
+ rows = SQLiteKit.query("SELECT id, title FROM items WHERE id IN :ids",
538
+ {"ids": [h["id"] for h in hits]}) # IN 不保证顺序,需按 hits 重排
539
+ ```
540
+
541
+ **自有事务内写向量(推荐:`build_insert_vectors` + `transaction()`)**:
542
+
543
+ ```python
544
+ from sqlalchemy import text
545
+
546
+ with SQLiteKit.transaction() as session: # 换成 PgKit / MySqlKit 写法相同
547
+ session.execute(text("INSERT INTO docs_item (id, title) VALUES (:id, :t)"),
548
+ {"id": doc_id, "t": title})
549
+ for sql, params in SQLiteKit.build_insert_vectors("docs_doc_vectors", vectors,
550
+ ids=row_ids, extra_data=metas,
551
+ id_col="rowid"):
552
+ session.execute(text(sql), params)
553
+ # 正常退出统一提交;异常自动回滚(多处写入保持同一事务)
554
+ ```
555
+
556
+ **SQLite 的 DBAPI 变体**(`raw_connection()` 支持 `:name` 命名参数):
557
+
558
+ ```python
559
+ conn = SQLiteKit.raw_connection() # 调用方负责 commit / close
560
+ try:
561
+ for sql, params in SQLiteKit.build_insert_vectors("item_vectors", vectors,
562
+ ids=row_ids, extra_data=metas):
563
+ conn.executemany(sql, params)
564
+ conn.commit()
565
+ finally:
566
+ conn.close()
567
+ ```
568
+
569
+ > ⚠ 两点约束:① `build_insert_vectors` 输出为 `:name` 风格,**PG / MySQL 的原生 DBAPI 不支持**
570
+ > (psycopg2 / pymysql 需 `%(name)s`),只能经 `transaction()` 的 session 执行;
571
+ > ② SQLite 上**持有未提交写事务**时再调 kit 的**自提交**方法(如 `insert_vectors`)会因另一个连接
572
+ > 拿不到写锁而失败(`OperationalError: database is locked`,约 **6.4s** 后才报错)——
573
+ > 把写入并入**同一个** `transaction()`(如上)即可避免。
574
+
575
+ > 相似度换算建议:SQLite 仅支持 L2,若向量入库前已**归一化**,则 `cos = 1 − L2²/2`;
576
+ > PG 可直接用 `distance_type="COSINE"`。
577
+
502
578
  ### 3. CRUDBase(配合 session_scope,不自动提交)
503
579
 
504
580
  ```python
@@ -266,7 +266,7 @@ from kit.db import session_scope, transactional, DBError # 推荐
266
266
  from kit import session_scope, transactional, DBError # 等价
267
267
  ```
268
268
 
269
- ### 1. 三个数据库 Kit(23 个共享方法 API 完全一致)
269
+ ### 1. 三个数据库 Kit(24 个共享方法 API 完全一致)
270
270
 
271
271
  | 类 | 导入 | 数据库 | extra |
272
272
  |----|------|--------|-------|
@@ -300,13 +300,23 @@ from kit import session_scope, transactional, DBError # 等价
300
300
  | 表 | `list_tables() -> list[str]` | 列出全部表名 |
301
301
  | 表 | `table_exists(table_name) -> bool` | 判断表是否存在 |
302
302
  | 表 | `create_tables(models) -> None` | 按模型列表建表 |
303
- | 表 | `get_table_info(table_name) -> list[dict]` | 获取列信息(三个 Kit 各自实现) |
303
+ | 表 | `get_table_info(table_name) -> list[dict]` | 获取列信息(按列序;公共键 4 个:`column_name`/`data_type`/`is_nullable`/`column_default`) |
304
+
305
+ > **列表参数(`IN`)**:`query` / `execute` 的 `params` 中值为 `list`/`tuple`/`set`/`frozenset`
306
+ > 时按 `IN` 展开,可直接写 `WHERE id IN :ids`(三库通用)。`IN` **不保证顺序**;参数列表过大
307
+ > 应分批(PG 单语句上限 65535 参数)。
308
+ >
309
+ > **`LIKE` 的方言差异**:SQLite 对 ASCII 不区分大小写,PostgreSQL 区分(用 `ILIKE`);
310
+ > 跨库一致写法:`LOWER(col) LIKE LOWER(:pattern)`。
311
+ >
312
+ > **导出面**:`from kit.db import PgKit, SQLiteKit, build_pg_url, to_vector_literal, …`
313
+ > (`kit` 顶层与 `kit.db` 导出同一套符号)。
304
314
 
305
315
  ```python
306
316
  from sqlalchemy import BigInteger
307
317
  from sqlmodel import SQLModel, Field
308
318
  from kit.common_kit import CommonKit
309
- from kit.db.sqlite_kit import SQLiteKit
319
+ from kit.db import SQLiteKit # 也可 from kit.db.sqlite_kit import SQLiteKit
310
320
 
311
321
  class User(SQLModel, table=True):
312
322
  # 主键:64 位整数 + 雪花 ID(应用侧生成,不用数据库自增)
@@ -323,6 +333,7 @@ users = SQLiteKit.list(User, skip=0, limit=10, order_by="id", desc=True)
323
333
 
324
334
  rows = SQLiteKit.query("SELECT * FROM user WHERE name = :name", {"name": "李四"})
325
335
  affected = SQLiteKit.execute("UPDATE user SET name = '王五' WHERE id = :id", {"id": user.id})
336
+ rows = SQLiteKit.query("SELECT * FROM user WHERE id IN :ids", {"ids": [1, 2, 3]}) # 列表参数
326
337
 
327
338
  with SQLiteKit.transaction() as session: # 多操作原子提交
328
339
  SQLiteKit.create(User, {"name": "批量一"})
@@ -343,8 +354,9 @@ with SQLiteKit.transaction() as session: # 多操作原子提
343
354
 
344
355
  | 方法 | 说明 |
345
356
  |------|------|
346
- | `create_vector_table(table_name, dims, id_col="id", column="embedding", extra_cols=None) -> None` | 建含向量列的表;**`dims` 必填**(SQLite 用 `CHECK` 落实为数据库层约束;PG 硬约束并回读校验已存在表;MySQL 为上限语义) |
347
- | `insert_vectors(table_name, vectors, ids=None, extra_data=None, id_col="id", column="embedding") -> int` | 批量插入向量(单事务提交);`ids=None` 时由 Kit 生成雪花 ID;接受 `list[list[float]]` 或二维 numpy 数组 |
357
+ | `create_vector_table(table_name, dims, id_col="id", column="embedding", extra_cols=None) -> None` | 建含向量列的表;**`dims` 必填**(SQLite 用 `CHECK` 落实为数据库层约束;PG 硬约束并回读校验已存在表;MySQL 为上限语义)。`extra_cols` 支持 `{列名: 类型串}`(推荐,与 `create_raw_table` 同形)与 `[{"name","type"}]` 两种形态 |
358
+ | `insert_vectors(table_name, vectors, ids=None, extra_data=None, id_col="id", column="embedding") -> int` | 批量插入向量(**自成一事务并提交**);`ids=None` 时由 Kit 生成雪花 ID;接受 `list[list[float]]` 或二维 numpy 数组 |
359
+ | `build_insert_vectors(table_name, vectors, ids=None, extra_data=None, id_col="id", column="embedding") -> list[tuple[str, list[dict]]]` | **只拼装、不执行、不管事务**:返回按列集分组的 `(SQL, 参数列表)`,供调用方在**自有事务**内写向量行(见「自有事务内写向量」) |
348
360
  | `search_vectors(table_name, query_vector, top_k=10, distance_type="L2", filter_sql=None, exact=True, id_col="id", column="embedding") -> list[dict]` | KNN 检索,按距离升序返回 `{"id", "distance"}`;`exact=True`(默认)禁止近似加速;**MySQL 侧抛 `VectorNotSupportedError`** |
349
361
  | `vector_version() -> str` | 向量后端版本;不可用时返回 `"unavailable"`(MySQL 侧为服务端版本号) |
350
362
 
@@ -429,6 +441,70 @@ PgKit.search_vectors("my_vec", [0.1] * 384, top_k=5, id_col="vid", column="vec")
429
441
  > 新增(非破坏性):`VECTOR_CAPABILITIES` 能力声明、`id_col` / `column` 逃生口参数、
430
442
  > `insert_vectors` 支持二维 numpy 数组与批量提交。
431
443
 
444
+ #### 0.2.4 变更
445
+
446
+ | 编号 | 变更 | 影响 |
447
+ |------|------|------|
448
+ | B4 | **入参自洽性校验**(`extra_data` 的键):保留绑定名 `id` / `vec`、与 `id_col` / `column` 重复、不是合法标识符、`id_col == column` → 抛可操作的 `ValueError` | **唯一行为变更**:此前 SQLite 会**静默写坏数据**(如 `id` 列被覆盖)、PG/MySQL 报误导性错误;正常调用**零影响** |
449
+ | — | 新增共享方法 `build_insert_vectors`(只拼装不执行,由 `BaseDbKit` 收敛 → 共享方法 23 → **24**) | 纯新增:可在**自有事务**内写向量行(见下) |
450
+ | — | `create_vector_table` 的 `extra_cols` 支持 `{列名: 类型串}`(与 `create_raw_table` 同形) | 纯新增:既有 `[{"name","type"}]` 形态保留,两者产出 DDL 逐字一致 |
451
+ | — | 后端差异收口:向量列占位符由 `VECTOR_PLACEHOLDER` 驱动(MySQL = `STRING_TO_VECTOR(:vec)`) | 内部整理:公开签名与行为不变 |
452
+ | — | `SQLiteKit.insert_vectors` 的事务获取统一为 `transaction()`(与另两库同构) | 内部一致:行为等价(自成一事务并提交) |
453
+
454
+ #### 0.2.3 变更
455
+
456
+ | 编号 | 变更 | 影响 |
457
+ |------|------|------|
458
+ | B6 | **`PgKit.get_table_info` 按数据库解析语义定位表**(`search_path` 解析到的那张表) | 多 schema 下同名表**不再混行**;单 schema / `public` 场景**无影响**;只接受非限定表名 |
459
+ | — | `query` / `execute` 支持**列表参数**(`IN :ids`,三库通用) | 纯新增;`set`/`frozenset` 自动归一化为 `list` |
460
+ | — | 新增 `SQLiteKit.encode_vector` / `decode_vector`(小端 float32) | 纯新增:可在自有事务内写向量表,见下 |
461
+ | — | 导出面统一:`from kit.db import PgKit, MySqlKit, SQLiteKit, build_pg_url, …` | 纯新增;既有导出未删除/未改名 |
462
+
463
+ **两段查询范式(推荐用法)**:`search_vectors` 只返回 `[{"id", "distance"}]`,载荷二次取回:
464
+
465
+ ```python
466
+ hits = SQLiteKit.search_vectors("item_vectors", query_vector, top_k=5)
467
+ rows = SQLiteKit.query("SELECT id, title FROM items WHERE id IN :ids",
468
+ {"ids": [h["id"] for h in hits]}) # IN 不保证顺序,需按 hits 重排
469
+ ```
470
+
471
+ **自有事务内写向量(推荐:`build_insert_vectors` + `transaction()`)**:
472
+
473
+ ```python
474
+ from sqlalchemy import text
475
+
476
+ with SQLiteKit.transaction() as session: # 换成 PgKit / MySqlKit 写法相同
477
+ session.execute(text("INSERT INTO docs_item (id, title) VALUES (:id, :t)"),
478
+ {"id": doc_id, "t": title})
479
+ for sql, params in SQLiteKit.build_insert_vectors("docs_doc_vectors", vectors,
480
+ ids=row_ids, extra_data=metas,
481
+ id_col="rowid"):
482
+ session.execute(text(sql), params)
483
+ # 正常退出统一提交;异常自动回滚(多处写入保持同一事务)
484
+ ```
485
+
486
+ **SQLite 的 DBAPI 变体**(`raw_connection()` 支持 `:name` 命名参数):
487
+
488
+ ```python
489
+ conn = SQLiteKit.raw_connection() # 调用方负责 commit / close
490
+ try:
491
+ for sql, params in SQLiteKit.build_insert_vectors("item_vectors", vectors,
492
+ ids=row_ids, extra_data=metas):
493
+ conn.executemany(sql, params)
494
+ conn.commit()
495
+ finally:
496
+ conn.close()
497
+ ```
498
+
499
+ > ⚠ 两点约束:① `build_insert_vectors` 输出为 `:name` 风格,**PG / MySQL 的原生 DBAPI 不支持**
500
+ > (psycopg2 / pymysql 需 `%(name)s`),只能经 `transaction()` 的 session 执行;
501
+ > ② SQLite 上**持有未提交写事务**时再调 kit 的**自提交**方法(如 `insert_vectors`)会因另一个连接
502
+ > 拿不到写锁而失败(`OperationalError: database is locked`,约 **6.4s** 后才报错)——
503
+ > 把写入并入**同一个** `transaction()`(如上)即可避免。
504
+
505
+ > 相似度换算建议:SQLite 仅支持 L2,若向量入库前已**归一化**,则 `cos = 1 − L2²/2`;
506
+ > PG 可直接用 `distance_type="COSINE"`。
507
+
432
508
  ### 3. CRUDBase(配合 session_scope,不自动提交)
433
509
 
434
510
  ```python
@@ -23,26 +23,37 @@ Author: Clark Chang
23
23
  数据库访问通过 kit.db 子包提供(基于 SQLModel)。
24
24
  """
25
25
 
26
- __version__ = "0.2.2"
26
+ __version__ = "0.2.4"
27
27
 
28
28
  from kit.db import (
29
29
  MYSQL,
30
30
  POSTGRESQL,
31
31
  SQLITE,
32
32
  CRUDBase,
33
+ DEFAULT_DISTANCE_TYPE,
33
34
  DBError,
35
+ MySqlKit,
34
36
  NotFoundError,
37
+ PgKit,
38
+ SQLiteKit,
39
+ VectorNotSupportedError,
40
+ build_mysql_url,
41
+ build_pg_url,
42
+ build_sqlite_url,
35
43
  close_all_engines,
36
44
  close_engine,
37
45
  create_tables,
46
+ generate_snowflake_ids,
38
47
  get_engine,
39
48
  get_session,
40
49
  list_tables,
41
50
  session_scope,
42
51
  table_exists,
52
+ to_vector_literal,
43
53
  transactional,
44
54
  )
45
55
 
56
+ # 顶层公共面与 kit.db 保持一致(同一套符号,避免两处入口漂移)
46
57
  __all__ = [
47
58
  # 引擎管理
48
59
  "get_engine",
@@ -51,18 +62,31 @@ __all__ = [
51
62
  "table_exists",
52
63
  "close_all_engines",
53
64
  "close_engine",
65
+ # 连接串构造(单一来源)
66
+ "build_pg_url",
67
+ "build_mysql_url",
68
+ "build_sqlite_url",
54
69
  # 常量
55
70
  "POSTGRESQL",
56
71
  "MYSQL",
57
72
  "SQLITE",
73
+ # 数据库 Kit
74
+ "PgKit",
75
+ "MySqlKit",
76
+ "SQLiteKit",
58
77
  # 会话
59
78
  "session_scope",
60
79
  "get_session",
61
80
  # 异常
62
81
  "DBError",
63
82
  "NotFoundError",
83
+ "VectorNotSupportedError",
64
84
  # CRUD
65
85
  "CRUDBase",
66
86
  # 事务
67
87
  "transactional",
88
+ # 向量工具(公共)
89
+ "to_vector_literal",
90
+ "generate_snowflake_ids",
91
+ "DEFAULT_DISTANCE_TYPE",
68
92
  ]
@@ -29,11 +29,19 @@ Author: Clark Chang
29
29
  - SQLModel 混入类(models/base.py)
30
30
  """
31
31
 
32
+ from kit.db.base_db_kit import (
33
+ DEFAULT_DISTANCE_TYPE,
34
+ generate_snowflake_ids,
35
+ to_vector_literal,
36
+ )
32
37
  from kit.db.crud import CRUDBase
33
38
  from kit.db.engine import (
34
39
  MYSQL,
35
40
  POSTGRESQL,
36
41
  SQLITE,
42
+ build_mysql_url,
43
+ build_pg_url,
44
+ build_sqlite_url,
37
45
  close_all_engines,
38
46
  close_engine,
39
47
  create_tables,
@@ -42,7 +50,10 @@ from kit.db.engine import (
42
50
  table_exists,
43
51
  )
44
52
  from kit.db.exceptions import DBError, NotFoundError, VectorNotSupportedError
53
+ from kit.db.mysql_kit import MySqlKit
54
+ from kit.db.pg_kit import PgKit
45
55
  from kit.db.session import get_session, session_scope
56
+ from kit.db.sqlite_kit import SQLiteKit
46
57
  from kit.db.transaction import transactional
47
58
 
48
59
  __all__ = [
@@ -53,10 +64,18 @@ __all__ = [
53
64
  "table_exists",
54
65
  "close_all_engines",
55
66
  "close_engine",
67
+ # 连接串构造(单一来源,测试/工具可复用)
68
+ "build_pg_url",
69
+ "build_mysql_url",
70
+ "build_sqlite_url",
56
71
  # 常量
57
72
  "POSTGRESQL",
58
73
  "MYSQL",
59
74
  "SQLITE",
75
+ # 数据库 Kit
76
+ "PgKit",
77
+ "MySqlKit",
78
+ "SQLiteKit",
60
79
  # 会话
61
80
  "session_scope",
62
81
  "get_session",
@@ -68,4 +87,8 @@ __all__ = [
68
87
  "CRUDBase",
69
88
  # 事务
70
89
  "transactional",
90
+ # 向量工具(公共)
91
+ "to_vector_literal",
92
+ "generate_snowflake_ids",
93
+ "DEFAULT_DISTANCE_TYPE",
71
94
  ]