sdpy-kit 0.1.2__tar.gz → 0.1.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.
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/PKG-INFO +17 -6
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/__init__.py +1 -1
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/base_service.py +62 -5
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/chat_service.py +49 -15
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/embedding_service.py +43 -23
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/image_service.py +3 -1
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/rerank_service.py +3 -1
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/pyproject.toml +18 -5
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/.gitignore +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/README.md +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/__init__.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/exceptions.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/failover.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/model_builder.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/model_client.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/pool.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/profiles.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/runner.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/ai/types.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/common_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/config/__init__.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/config/kit_config.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/config/log_config.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/__init__.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/base_db_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/crud.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/engine.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/exceptions.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/models/__init__.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/models/base.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/mysql_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/pg_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/query.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/session.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/sqlite_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/db/transaction.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/doc_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/file_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/mcp_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/mineru_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/kit/redis_kit.py +0 -0
- {sdpy_kit-0.1.2 → sdpy_kit-0.1.4}/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.1.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
|
|
@@ -17,23 +17,34 @@ Classifier: Topic :: Database
|
|
|
17
17
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
19
|
Requires-Python: >=3.13
|
|
20
|
-
Requires-Dist: fastmcp>=4.0.3
|
|
21
20
|
Requires-Dist: firecrawl-anydoc>=0.2.4
|
|
22
21
|
Requires-Dist: httpx>=0.28.1
|
|
23
22
|
Requires-Dist: markdown-it-py>=3.0
|
|
24
23
|
Requires-Dist: numpy>=2.0
|
|
25
24
|
Requires-Dist: pimd[pdfa]>=2.2.5
|
|
26
|
-
Requires-Dist: psycopg2-binary>=2.9.12
|
|
27
25
|
Requires-Dist: pydantic-settings>=2.0
|
|
28
26
|
Requires-Dist: pydantic>=2.0
|
|
29
|
-
Requires-Dist: pymysql>=1.2.0
|
|
30
27
|
Requires-Dist: python-dotenv>=1.2.3
|
|
31
|
-
Requires-Dist: redis>=5.0.0
|
|
32
28
|
Requires-Dist: requests>=2.34.0
|
|
33
29
|
Requires-Dist: sqlalchemy~=2.0.51
|
|
34
30
|
Requires-Dist: sqliteai-vector>=1.0.0
|
|
35
31
|
Requires-Dist: sqlmodel>=0.0.39
|
|
36
|
-
|
|
32
|
+
Provides-Extra: all
|
|
33
|
+
Requires-Dist: fastmcp>=4.0.3; extra == 'all'
|
|
34
|
+
Requires-Dist: psycopg2-binary>=2.9.12; extra == 'all'
|
|
35
|
+
Requires-Dist: pymysql>=1.2.0; extra == 'all'
|
|
36
|
+
Requires-Dist: redis>=5.0.0; extra == 'all'
|
|
37
|
+
Requires-Dist: zvec>=0.6.0; extra == 'all'
|
|
38
|
+
Provides-Extra: mcp
|
|
39
|
+
Requires-Dist: fastmcp>=4.0.3; extra == 'mcp'
|
|
40
|
+
Provides-Extra: mysql
|
|
41
|
+
Requires-Dist: pymysql>=1.2.0; extra == 'mysql'
|
|
42
|
+
Provides-Extra: pg
|
|
43
|
+
Requires-Dist: psycopg2-binary>=2.9.12; extra == 'pg'
|
|
44
|
+
Provides-Extra: redis
|
|
45
|
+
Requires-Dist: redis>=5.0.0; extra == 'redis'
|
|
46
|
+
Provides-Extra: zvec
|
|
47
|
+
Requires-Dist: zvec>=0.6.0; extra == 'zvec'
|
|
37
48
|
Description-Content-Type: text/markdown
|
|
38
49
|
|
|
39
50
|
# sdpy-kit
|
|
@@ -17,16 +17,25 @@ Project: sdpy
|
|
|
17
17
|
Author: Clark Chang
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
|
+
import json
|
|
21
|
+
import time
|
|
20
22
|
from abc import ABC, abstractmethod
|
|
21
|
-
from typing import Self, override
|
|
23
|
+
from typing import ClassVar, Final, Self, override
|
|
22
24
|
|
|
23
|
-
from kit.ai.exceptions import AIResponseError
|
|
25
|
+
from kit.ai.exceptions import AIError, AIResponseError
|
|
24
26
|
from kit.ai.model_client import ModelClient
|
|
25
27
|
from kit.ai.profiles import ModelProfile
|
|
26
28
|
from kit.ai.types import JSONObject, JSONValue
|
|
29
|
+
from kit.config.log_config import get_default_logger
|
|
27
30
|
|
|
28
31
|
__all__ = ["BaseAIService", "safe_get"]
|
|
29
32
|
|
|
33
|
+
logger = get_default_logger(__name__)
|
|
34
|
+
|
|
35
|
+
# 日志打印请求参数的截断上限:单字段字符数 / 参数总字符数
|
|
36
|
+
_LOG_FIELD_LIMIT: Final[int] = 200
|
|
37
|
+
_LOG_PAYLOAD_LIMIT: Final[int] = 2000
|
|
38
|
+
|
|
30
39
|
|
|
31
40
|
def safe_get(data: JSONValue, *path: str | int) -> JSONValue:
|
|
32
41
|
"""按层级路径安全取值,支持 dict 键(str)与 list 索引(int)。
|
|
@@ -49,6 +58,26 @@ def safe_get(data: JSONValue, *path: str | int) -> JSONValue:
|
|
|
49
58
|
return cur
|
|
50
59
|
|
|
51
60
|
|
|
61
|
+
def _clip(value: JSONValue) -> JSONValue:
|
|
62
|
+
"""递归裁剪过长字符串字段(日志打印参数用,单字段上限 _LOG_FIELD_LIMIT)。"""
|
|
63
|
+
if isinstance(value, str):
|
|
64
|
+
if len(value) > _LOG_FIELD_LIMIT:
|
|
65
|
+
return f"{value[:_LOG_FIELD_LIMIT]}…(截断)"
|
|
66
|
+
return value
|
|
67
|
+
if isinstance(value, list):
|
|
68
|
+
return [_clip(item) for item in value]
|
|
69
|
+
if isinstance(value, dict):
|
|
70
|
+
return {key: _clip(item) for key, item in value.items()}
|
|
71
|
+
return value
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _truncate(text: str, limit: int) -> str:
|
|
75
|
+
"""超长文本按上限截断,尾部追加截断标记(日志打印参数总长用)。"""
|
|
76
|
+
if len(text) > limit:
|
|
77
|
+
return f"{text[:limit]}…(截断)"
|
|
78
|
+
return text
|
|
79
|
+
|
|
80
|
+
|
|
52
81
|
class BaseAIService[RequestT, ResponseT](ABC):
|
|
53
82
|
"""AI 服务基类(模板方法 + 泛型)。
|
|
54
83
|
|
|
@@ -58,6 +87,9 @@ class BaseAIService[RequestT, ResponseT](ABC):
|
|
|
58
87
|
类型 ``ResponseT`` 由泛型绑定,保证覆写签名一致、类型自洽。
|
|
59
88
|
"""
|
|
60
89
|
|
|
90
|
+
# 日志「模型及描述」中的服务中文名,子类覆写
|
|
91
|
+
_LABEL: ClassVar[str] = "模型"
|
|
92
|
+
|
|
61
93
|
def __init__(self, profile: ModelProfile) -> None:
|
|
62
94
|
self._profile: ModelProfile = profile
|
|
63
95
|
self._client: ModelClient = ModelClient(profile)
|
|
@@ -66,6 +98,13 @@ class BaseAIService[RequestT, ResponseT](ABC):
|
|
|
66
98
|
def profile(self) -> ModelProfile:
|
|
67
99
|
return self._profile
|
|
68
100
|
|
|
101
|
+
def _log_desc(self, *, suffix: str = "") -> str:
|
|
102
|
+
"""日志中的「模型及描述」:服务中文名 + 模型标识 + 实例名。"""
|
|
103
|
+
return (
|
|
104
|
+
f"{self._LABEL} {self._profile.model}"
|
|
105
|
+
f"(实例 {self._profile.name}{suffix})"
|
|
106
|
+
)
|
|
107
|
+
|
|
69
108
|
@abstractmethod
|
|
70
109
|
def _build_payload(self, request: RequestT) -> JSONObject:
|
|
71
110
|
"""将请求模型构造为 JSON 请求体。"""
|
|
@@ -75,10 +114,28 @@ class BaseAIService[RequestT, ResponseT](ABC):
|
|
|
75
114
|
"""将 JSON 响应体解析为业务结果。"""
|
|
76
115
|
|
|
77
116
|
async def _call(self, request: RequestT) -> ResponseT:
|
|
78
|
-
"""统一编排:构造请求体 → 发送 →
|
|
117
|
+
"""统一编排:构造请求体 → 发送 → 解析响应(含中文 info 日志)。"""
|
|
118
|
+
desc = self._log_desc()
|
|
79
119
|
payload = self._build_payload(request)
|
|
80
|
-
|
|
81
|
-
|
|
120
|
+
params = _truncate(
|
|
121
|
+
json.dumps(_clip(payload), ensure_ascii=False), _LOG_PAYLOAD_LIMIT
|
|
122
|
+
)
|
|
123
|
+
logger.info(f"********** {desc} ********** Start")
|
|
124
|
+
logger.info(f"请求参数: {params}")
|
|
125
|
+
start = time.perf_counter()
|
|
126
|
+
try:
|
|
127
|
+
data = await self._client.post_json(payload)
|
|
128
|
+
result = self._parse_response(data)
|
|
129
|
+
except AIError as exc:
|
|
130
|
+
logger.error(
|
|
131
|
+
f"********** {desc} ********** "
|
|
132
|
+
f"耗时 {time.perf_counter() - start:.1f}秒(失败:{exc})"
|
|
133
|
+
)
|
|
134
|
+
raise
|
|
135
|
+
logger.info(
|
|
136
|
+
f"********** {desc} ********** 耗时 {time.perf_counter() - start:.1f}秒"
|
|
137
|
+
)
|
|
138
|
+
return result
|
|
82
139
|
|
|
83
140
|
async def close(self) -> None:
|
|
84
141
|
await self._client.close()
|
|
@@ -17,12 +17,20 @@ Project: sdpy
|
|
|
17
17
|
Author: Clark Chang
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
|
+
import json
|
|
21
|
+
import time
|
|
20
22
|
from collections.abc import AsyncIterator
|
|
21
23
|
from dataclasses import dataclass
|
|
22
|
-
from typing import cast, override
|
|
23
|
-
|
|
24
|
-
from kit.ai.base_service import
|
|
25
|
-
|
|
24
|
+
from typing import ClassVar, cast, override
|
|
25
|
+
|
|
26
|
+
from kit.ai.base_service import (
|
|
27
|
+
_LOG_PAYLOAD_LIMIT,
|
|
28
|
+
BaseAIService,
|
|
29
|
+
_clip,
|
|
30
|
+
_truncate,
|
|
31
|
+
safe_get,
|
|
32
|
+
)
|
|
33
|
+
from kit.ai.exceptions import AIError, AIResponseError
|
|
26
34
|
from kit.ai.types import JSONObject
|
|
27
35
|
from kit.config.log_config import get_default_logger
|
|
28
36
|
|
|
@@ -46,6 +54,8 @@ class ChatRequest:
|
|
|
46
54
|
class ChatService(BaseAIService[ChatRequest, str]):
|
|
47
55
|
"""对话类模型服务(全异步)。"""
|
|
48
56
|
|
|
57
|
+
_LABEL: ClassVar[str] = "对话模型"
|
|
58
|
+
|
|
49
59
|
@override
|
|
50
60
|
def _build_payload(self, request: ChatRequest) -> JSONObject:
|
|
51
61
|
payload: dict[str, object] = {
|
|
@@ -97,14 +107,38 @@ class ChatService(BaseAIService[ChatRequest, str]):
|
|
|
97
107
|
messages, temperature=temperature, max_tokens=max_tokens, stream=True
|
|
98
108
|
)
|
|
99
109
|
payload = self._build_payload(request)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
desc = self._log_desc()
|
|
111
|
+
params = _truncate(
|
|
112
|
+
json.dumps(_clip(payload), ensure_ascii=False), _LOG_PAYLOAD_LIMIT
|
|
113
|
+
)
|
|
114
|
+
# 惰性 Start:异步生成器体在首次 __anext__ 前不执行,不消费不打日志
|
|
115
|
+
logger.info(f"********** {desc} ********** Start")
|
|
116
|
+
logger.info(f"请求参数: {params}")
|
|
117
|
+
start = time.perf_counter()
|
|
118
|
+
note = ""
|
|
119
|
+
failed = False
|
|
120
|
+
try:
|
|
121
|
+
async for parsed in self._client.stream_json(payload):
|
|
122
|
+
if parsed is None:
|
|
123
|
+
continue
|
|
124
|
+
try:
|
|
125
|
+
delta = safe_get(parsed, "choices", 0, "delta", "content")
|
|
126
|
+
except AIResponseError:
|
|
127
|
+
# 流式结束帧等无 delta 的正常帧,跳过
|
|
128
|
+
logger.debug("流式帧缺少 delta.content,跳过")
|
|
129
|
+
continue
|
|
130
|
+
if isinstance(delta, str) and delta:
|
|
131
|
+
yield delta
|
|
132
|
+
except AIError as exc:
|
|
133
|
+
note = f"(失败:{exc})"
|
|
134
|
+
failed = True
|
|
135
|
+
raise
|
|
136
|
+
except BaseException: # noqa: BLE001 - 中断路径(提前 break/取消)也需收尾日志
|
|
137
|
+
note = "(中断)"
|
|
138
|
+
raise
|
|
139
|
+
finally:
|
|
140
|
+
log = logger.error if failed else logger.info
|
|
141
|
+
log(
|
|
142
|
+
f"********** {desc} ********** "
|
|
143
|
+
f"耗时 {time.perf_counter() - start:.1f}秒{note}"
|
|
144
|
+
)
|
|
@@ -19,6 +19,7 @@ Author: Clark Chang
|
|
|
19
19
|
|
|
20
20
|
import asyncio
|
|
21
21
|
import itertools
|
|
22
|
+
import time
|
|
22
23
|
from dataclasses import dataclass
|
|
23
24
|
from typing import cast, override
|
|
24
25
|
|
|
@@ -26,9 +27,12 @@ from kit.ai.base_service import BaseAIService, safe_get
|
|
|
26
27
|
from kit.ai.exceptions import AIError, AIRequestError, AIResponseError
|
|
27
28
|
from kit.ai.profiles import ModelProfile
|
|
28
29
|
from kit.ai.types import JSONObject
|
|
30
|
+
from kit.config.log_config import get_default_logger
|
|
29
31
|
|
|
30
32
|
__all__ = ["EmbeddingRequest", "EmbeddingService"]
|
|
31
33
|
|
|
34
|
+
logger = get_default_logger(__name__)
|
|
35
|
+
|
|
32
36
|
_DEFAULT_CONCURRENCY = 4
|
|
33
37
|
|
|
34
38
|
|
|
@@ -106,28 +110,44 @@ class EmbeddingService(BaseAIService[EmbeddingRequest, list[list[float]]]):
|
|
|
106
110
|
return []
|
|
107
111
|
|
|
108
112
|
batch = batch_size or self._profile.batch_size
|
|
109
|
-
semaphore = asyncio.Semaphore(concurrency)
|
|
110
|
-
results: list[list[float] | None] = [None] * len(texts)
|
|
111
|
-
failures: list[str] = []
|
|
112
|
-
|
|
113
|
-
async def _one(batch_index: int, chunk: tuple[str, ...]) -> None:
|
|
114
|
-
async with semaphore:
|
|
115
|
-
try:
|
|
116
|
-
vectors = await self._call(EmbeddingRequest(list(chunk)))
|
|
117
|
-
except AIError as exc:
|
|
118
|
-
failures.append(f"批次 {batch_index}: {exc}")
|
|
119
|
-
return
|
|
120
|
-
start = batch_index * batch
|
|
121
|
-
for offset, vec in enumerate(vectors):
|
|
122
|
-
results[start + offset] = vec
|
|
123
|
-
|
|
124
113
|
batches = list(itertools.batched(texts, batch, strict=False))
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
114
|
+
desc = self._log_desc(suffix=",整批汇总")
|
|
115
|
+
logger.info(f"********** {desc} ********** Start")
|
|
116
|
+
logger.info(
|
|
117
|
+
f"请求参数: 共 {len(texts)} 条文本,分 {len(batches)} 批"
|
|
118
|
+
f"(批大小 {batch},并发 {concurrency})"
|
|
119
|
+
)
|
|
120
|
+
start = time.perf_counter()
|
|
121
|
+
note = ""
|
|
122
|
+
try:
|
|
123
|
+
semaphore = asyncio.Semaphore(concurrency)
|
|
124
|
+
results: list[list[float] | None] = [None] * len(texts)
|
|
125
|
+
failures: list[str] = []
|
|
126
|
+
|
|
127
|
+
async def _one(batch_index: int, chunk: tuple[str, ...]) -> None:
|
|
128
|
+
async with semaphore:
|
|
129
|
+
try:
|
|
130
|
+
vectors = await self._call(EmbeddingRequest(list(chunk)))
|
|
131
|
+
except AIError as exc:
|
|
132
|
+
failures.append(f"批次 {batch_index}: {exc}")
|
|
133
|
+
return
|
|
134
|
+
start = batch_index * batch
|
|
135
|
+
for offset, vec in enumerate(vectors):
|
|
136
|
+
results[start + offset] = vec
|
|
137
|
+
|
|
138
|
+
await asyncio.gather(*(_one(i, chunk) for i, chunk in enumerate(batches)))
|
|
139
|
+
|
|
140
|
+
if failures:
|
|
141
|
+
note = f"(失败:{len(failures)}/{len(batches)} 批)"
|
|
142
|
+
raise AIRequestError(
|
|
143
|
+
f"有 {len(failures)}/{len(batches)} 批向量化失败: "
|
|
144
|
+
+ " | ".join(failures)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return [vec for vec in results if vec is not None]
|
|
148
|
+
finally:
|
|
149
|
+
log = logger.error if failures else logger.info
|
|
150
|
+
log(
|
|
151
|
+
f"********** {desc} ********** "
|
|
152
|
+
f"耗时 {time.perf_counter() - start:.1f}秒{note}"
|
|
131
153
|
)
|
|
132
|
-
|
|
133
|
-
return [vec for vec in results if vec is not None]
|
|
@@ -18,7 +18,7 @@ Author: Clark Chang
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
from dataclasses import dataclass
|
|
21
|
-
from typing import override
|
|
21
|
+
from typing import ClassVar, override
|
|
22
22
|
|
|
23
23
|
from kit.ai.base_service import BaseAIService, safe_get
|
|
24
24
|
from kit.ai.exceptions import AIResponseError
|
|
@@ -52,6 +52,8 @@ class ImageService(BaseAIService[ImageRequest, str]):
|
|
|
52
52
|
返回 Base64 数据,调用方按返回值是否以 ``http`` 开头区分形式。
|
|
53
53
|
"""
|
|
54
54
|
|
|
55
|
+
_LABEL: ClassVar[str] = "图像生成模型"
|
|
56
|
+
|
|
55
57
|
@override
|
|
56
58
|
def _build_payload(self, request: ImageRequest) -> JSONObject:
|
|
57
59
|
payload: JSONObject = {
|
|
@@ -18,7 +18,7 @@ Author: Clark Chang
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
from dataclasses import dataclass
|
|
21
|
-
from typing import cast, override
|
|
21
|
+
from typing import ClassVar, cast, override
|
|
22
22
|
|
|
23
23
|
from kit.ai.base_service import BaseAIService, safe_get
|
|
24
24
|
from kit.ai.exceptions import AIResponseError
|
|
@@ -47,6 +47,8 @@ class RerankHit:
|
|
|
47
47
|
class RerankService(BaseAIService[RerankRequest, list[RerankHit]]):
|
|
48
48
|
"""重排序服务(全异步)。"""
|
|
49
49
|
|
|
50
|
+
_LABEL: ClassVar[str] = "重排序模型"
|
|
51
|
+
|
|
50
52
|
@override
|
|
51
53
|
def _build_payload(self, request: RerankRequest) -> JSONObject:
|
|
52
54
|
payload: dict[str, object] = {
|
|
@@ -34,21 +34,34 @@ dependencies = [
|
|
|
34
34
|
"numpy>=2.0",
|
|
35
35
|
"sqlalchemy~=2.0.51",
|
|
36
36
|
"sqlmodel>=0.0.39",
|
|
37
|
-
"pymysql>=1.2.0",
|
|
38
|
-
"psycopg2-binary>=2.9.12",
|
|
39
|
-
"redis>=5.0.0",
|
|
40
|
-
"zvec>=0.6.0",
|
|
41
37
|
"sqliteai-vector>=1.0.0",
|
|
42
38
|
"firecrawl-anydoc>=0.2.4",
|
|
43
39
|
"pimd[pdfa]>=2.2.5",
|
|
44
40
|
"markdown-it-py>=3.0",
|
|
45
|
-
"fastmcp>=4.0.3",
|
|
46
41
|
"httpx>=0.28.1",
|
|
47
42
|
"requests>=2.34.0",
|
|
48
43
|
"python-dotenv>=1.2.3",
|
|
49
44
|
]
|
|
50
45
|
dynamic = ["version"]
|
|
51
46
|
|
|
47
|
+
# 关键节点:可选后端按 extras 拆分(0.1.4)。fastmcp/zvec/redis/psycopg2/pymysql
|
|
48
|
+
# 仅在对应 Kit(mcp_kit/zvec_kit/redis_kit/pg_kit/mysql_kit)被实际使用时才需
|
|
49
|
+
# 安装,且均为延迟导入——不装 extras 时 import kit 与基础 Kit 全部可用。
|
|
50
|
+
# 单机 SQLite 场景安装基础版即可,避免拖入重依赖(原全量安装多占约 60MB)。
|
|
51
|
+
[project.optional-dependencies]
|
|
52
|
+
pg = ["psycopg2-binary>=2.9.12"]
|
|
53
|
+
mysql = ["pymysql>=1.2.0"]
|
|
54
|
+
redis = ["redis>=5.0.0"]
|
|
55
|
+
zvec = ["zvec>=0.6.0"]
|
|
56
|
+
mcp = ["fastmcp>=4.0.3"]
|
|
57
|
+
all = [
|
|
58
|
+
"psycopg2-binary>=2.9.12",
|
|
59
|
+
"pymysql>=1.2.0",
|
|
60
|
+
"redis>=5.0.0",
|
|
61
|
+
"zvec>=0.6.0",
|
|
62
|
+
"fastmcp>=4.0.3",
|
|
63
|
+
]
|
|
64
|
+
|
|
52
65
|
[tool.hatch.version]
|
|
53
66
|
path = "kit/__init__.py"
|
|
54
67
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|