agentic-kit-common 0.0.11__tar.gz → 0.0.21__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.
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/PKG-INFO +7 -1
- agentic_kit_common-0.0.21/agentic_kit_common/config/__init__.py +21 -0
- agentic_kit_common-0.0.21/agentic_kit_common/config/config_loader.py +311 -0
- agentic_kit_common-0.0.21/agentic_kit_common/llm/__init__.py +2 -0
- agentic_kit_common-0.0.21/agentic_kit_common/llm/openai.py +33 -0
- agentic_kit_common-0.0.21/agentic_kit_common/llm/utils.py +61 -0
- agentic_kit_common-0.0.21/agentic_kit_common/log/logger.py +69 -0
- agentic_kit_common-0.0.21/agentic_kit_common/mcp/mcp_client.py +344 -0
- agentic_kit_common-0.0.21/agentic_kit_common/mongodb/__init__.py +2 -0
- agentic_kit_common-0.0.21/agentic_kit_common/mongodb/mongodb_manager.py +294 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/execution.py +1 -1
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/multi_session.py +4 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/schema.py +2 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/session.py +2 -2
- agentic_kit_common-0.0.21/agentic_kit_common/redis/redis_pool_manager.py +118 -0
- agentic_kit_common-0.0.21/agentic_kit_common/sms/ali_sms_client.py +54 -0
- agentic_kit_common-0.0.21/agentic_kit_common/web/__init__.py +0 -0
- agentic_kit_common-0.0.21/agentic_kit_common/web/http/__init__.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/PKG-INFO +7 -1
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/SOURCES.txt +16 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/requires.txt +6 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/setup.py +13 -1
- agentic_kit_common-0.0.21/test/__init__.py +0 -0
- agentic_kit_common-0.0.21/test/conf.yaml +56 -0
- agentic_kit_common-0.0.21/test/test_config_manager.py +29 -0
- agentic_kit_common-0.0.21/test/test_mcp_client.py +29 -0
- agentic_kit_common-0.0.11/agentic_kit_common/log/logger.py +0 -16
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/README.md +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/__init__.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/log/__init__.py +0 -0
- {agentic_kit_common-0.0.11/agentic_kit_common/minio → agentic_kit_common-0.0.21/agentic_kit_common/mcp}/__init__.py +0 -0
- {agentic_kit_common-0.0.11/agentic_kit_common/vector → agentic_kit_common-0.0.21/agentic_kit_common/minio}/__init__.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/minio/minio_manager.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/__init__.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/base.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/orm/manager.py +0 -0
- {agentic_kit_common-0.0.11/agentic_kit_common/web → agentic_kit_common-0.0.21/agentic_kit_common/redis}/__init__.py +0 -0
- {agentic_kit_common-0.0.11/agentic_kit_common/web/http → agentic_kit_common-0.0.21/agentic_kit_common/sms}/__init__.py +0 -0
- {agentic_kit_common-0.0.11/test → agentic_kit_common-0.0.21/agentic_kit_common/vector}/__init__.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/embedding/__init__.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/embedding/embedding.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/manager/__init__.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/manager/milvus_manager.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/schema/__init__.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/schema/base.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/vector/schema/milvus_schema.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common/web/http/response.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/dependency_links.txt +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/agentic_kit_common.egg-info/top_level.txt +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/setup.cfg +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/test/config.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/test/settings.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/test/test_embedding.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/test/test_minio.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/test/test_orm.py +0 -0
- {agentic_kit_common-0.0.11 → agentic_kit_common-0.0.21}/test/test_vector.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentic-kit-common
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.21
|
|
4
4
|
Summary: Common utilities and tools for agentic kit ecosystem
|
|
5
5
|
Home-page:
|
|
6
6
|
Author: manson
|
|
@@ -24,11 +24,17 @@ Requires-Dist: langchain_core
|
|
|
24
24
|
Requires-Dist: langgraph
|
|
25
25
|
Requires-Dist: langchain_community
|
|
26
26
|
Requires-Dist: langchain_experimental
|
|
27
|
+
Requires-Dist: langchain-openai
|
|
28
|
+
Requires-Dist: langchain_mcp_adapters
|
|
27
29
|
Requires-Dist: mysql-connector-python
|
|
28
30
|
Requires-Dist: sqlalchemy
|
|
29
31
|
Requires-Dist: sqlglot
|
|
30
32
|
Requires-Dist: pymilvus
|
|
31
33
|
Requires-Dist: xinference_client
|
|
34
|
+
Requires-Dist: pymongo
|
|
35
|
+
Requires-Dist: redis
|
|
36
|
+
Requires-Dist: aliyun-python-sdk-core
|
|
37
|
+
Requires-Dist: aliyun-python-sdk-dysmsapi
|
|
32
38
|
Dynamic: author
|
|
33
39
|
Dynamic: author-email
|
|
34
40
|
Dynamic: classifier
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .config_loader import (
|
|
2
|
+
ConfigManager,
|
|
3
|
+
load_config,
|
|
4
|
+
get_llm_config,
|
|
5
|
+
get_rag_config,
|
|
6
|
+
get_database_config,
|
|
7
|
+
get_full_config,
|
|
8
|
+
reload_config,
|
|
9
|
+
set_config_manager,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"ConfigManager",
|
|
14
|
+
"set_config_manager",
|
|
15
|
+
"load_config",
|
|
16
|
+
"get_llm_config",
|
|
17
|
+
"get_rag_config",
|
|
18
|
+
"get_database_config",
|
|
19
|
+
"get_full_config",
|
|
20
|
+
"reload_config",
|
|
21
|
+
]
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
import yaml
|
|
6
|
+
from dotenv import load_dotenv, find_dotenv
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
load_dotenv(find_dotenv(usecwd=True))
|
|
12
|
+
_config_root_path = os.getenv("DELTA_CONFIG_PATH", None)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ConfigManager:
|
|
16
|
+
"""
|
|
17
|
+
配置管理器 - 支持多种配置源
|
|
18
|
+
|
|
19
|
+
支持的配置方式(优先级从高到低):
|
|
20
|
+
1. 环境变量(最高优先级)
|
|
21
|
+
2. 初始化时传入的 config 参数
|
|
22
|
+
3. 配置文件(config_path 或默认的 conf.yaml)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
config: Optional[Dict[str, Any]] = None,
|
|
28
|
+
config_path: Optional[str] = None
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
初始化配置管理器
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
config: 直接传入的配置字典(适合外部 SDK 调用)
|
|
35
|
+
格式示例:
|
|
36
|
+
{
|
|
37
|
+
"BASIC_MODEL": {
|
|
38
|
+
"base_url": "http://...",
|
|
39
|
+
"model": "qwen",
|
|
40
|
+
"api_key": "sk-xxx"
|
|
41
|
+
},
|
|
42
|
+
"VISION_MODEL": {
|
|
43
|
+
"base_url": "http://...",
|
|
44
|
+
"model": "vision",
|
|
45
|
+
"api_key": "sk-xxx"
|
|
46
|
+
},
|
|
47
|
+
"RAG_CLIENT": {
|
|
48
|
+
"base_url": "http://...",
|
|
49
|
+
"timeout": 120
|
|
50
|
+
},
|
|
51
|
+
"DATABASE_CLIENT": {
|
|
52
|
+
"base_url": "http://...",
|
|
53
|
+
"timeout": 120
|
|
54
|
+
},
|
|
55
|
+
"MCP_SETTINGS": {
|
|
56
|
+
"default_servers": {
|
|
57
|
+
"file-processor": {
|
|
58
|
+
"transport": "streamable_http",
|
|
59
|
+
"url": "http://...",
|
|
60
|
+
"enabled_tools": ["convert_to_markdown"]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
config_path: 配置文件路径(可选)
|
|
67
|
+
- 如果不提供,默认使用项目根目录的 conf.yaml
|
|
68
|
+
- 如果提供,使用指定路径的配置文件
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
# 方式1: 直接传入配置(外部 SDK 推荐)
|
|
72
|
+
config_mgr = ConfigManager(config={
|
|
73
|
+
"BASIC_MODEL": {...},
|
|
74
|
+
"RAG_CLIENT": {...}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
# 方式2: 指定配置文件路径
|
|
78
|
+
config_mgr = ConfigManager(config_path="/path/to/conf.yaml")
|
|
79
|
+
|
|
80
|
+
# 方式3: 使用默认配置文件(项目根目录/conf.yaml)
|
|
81
|
+
config_mgr = ConfigManager()
|
|
82
|
+
"""
|
|
83
|
+
self._external_config = config or {}
|
|
84
|
+
self._config_path = config_path or _config_root_path
|
|
85
|
+
self._config_cache: Optional[Dict[str, Any]] = None
|
|
86
|
+
|
|
87
|
+
def load_config(self, force_reload: bool = False) -> Dict[str, Any]:
|
|
88
|
+
"""
|
|
89
|
+
加载配置(带缓存)
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
force_reload: 是否强制重新加载
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Dict[str, Any]: 完整配置字典
|
|
96
|
+
"""
|
|
97
|
+
if self._config_cache is not None and not force_reload:
|
|
98
|
+
return self._config_cache
|
|
99
|
+
|
|
100
|
+
# 如果有外部配置,直接使用
|
|
101
|
+
if self._external_config:
|
|
102
|
+
self._config_cache = self._external_config.copy()
|
|
103
|
+
logger.info("使用外部传入的配置")
|
|
104
|
+
return self._config_cache
|
|
105
|
+
|
|
106
|
+
# 从配置文件加载
|
|
107
|
+
conf_path = self._config_path
|
|
108
|
+
|
|
109
|
+
if not os.path.exists(conf_path):
|
|
110
|
+
logger.warning(f"配置文件不存在: {conf_path},使用空配置")
|
|
111
|
+
self._config_cache = {}
|
|
112
|
+
return self._config_cache
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
with open(conf_path, 'r', encoding='utf-8') as f:
|
|
116
|
+
config = yaml.safe_load(f) or {}
|
|
117
|
+
self._config_cache = config
|
|
118
|
+
logger.info(f"成功加载配置文件: {conf_path}")
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.error(f"加载配置文件失败: {e}")
|
|
121
|
+
self._config_cache = {}
|
|
122
|
+
|
|
123
|
+
return self._config_cache
|
|
124
|
+
|
|
125
|
+
def get_llm_config(self, model_type: str = "BASIC_MODEL") -> Dict[str, Any]:
|
|
126
|
+
"""
|
|
127
|
+
获取LLM配置
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
model_type: 模型类型,可选 "BASIC_MODEL", "VISION_MODEL"
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Dict[str, Any]: LLM配置
|
|
134
|
+
"""
|
|
135
|
+
config = self.load_config()
|
|
136
|
+
base_config = config.get(model_type, {}).copy() if isinstance(config.get(model_type), dict) else {}
|
|
137
|
+
|
|
138
|
+
# 环境变量覆盖(优先级最高)
|
|
139
|
+
prefix = f"{model_type}__"
|
|
140
|
+
for key, value in os.environ.items():
|
|
141
|
+
if key.startswith(prefix):
|
|
142
|
+
conf_key = key[len(prefix):].lower()
|
|
143
|
+
base_config[conf_key] = value
|
|
144
|
+
|
|
145
|
+
return base_config
|
|
146
|
+
|
|
147
|
+
def get_rag_config(self) -> Dict[str, Any]:
|
|
148
|
+
"""
|
|
149
|
+
获取RAG客户端配置
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Dict[str, Any]: RAG配置
|
|
153
|
+
"""
|
|
154
|
+
config = self.load_config()
|
|
155
|
+
rag_config = config.get("RAG_CLIENT", {}).copy() if isinstance(config.get("RAG_CLIENT"), dict) else {}
|
|
156
|
+
|
|
157
|
+
# 支持环境变量覆盖
|
|
158
|
+
env_overrides = {
|
|
159
|
+
"base_url": os.getenv("RAG_CLIENT__base_url"),
|
|
160
|
+
"timeout": os.getenv("RAG_CLIENT__timeout"),
|
|
161
|
+
"max_retries": os.getenv("RAG_CLIENT__max_retries"),
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for key, value in env_overrides.items():
|
|
165
|
+
if value is not None:
|
|
166
|
+
rag_config[key] = value
|
|
167
|
+
|
|
168
|
+
return rag_config
|
|
169
|
+
|
|
170
|
+
def get_mcp_config(self) -> Dict[str, Any]:
|
|
171
|
+
"""
|
|
172
|
+
获取MCP服务器配置
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Dict[str, Any]: MCP配置
|
|
176
|
+
"""
|
|
177
|
+
config = self.load_config()
|
|
178
|
+
return config.get("MCP_SETTINGS", {})
|
|
179
|
+
|
|
180
|
+
def get_database_config(self) -> Dict[str, Any]:
|
|
181
|
+
"""
|
|
182
|
+
获取数据库客户端配置
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Dict[str, Any]: 数据库配置
|
|
186
|
+
"""
|
|
187
|
+
config = self.load_config()
|
|
188
|
+
db_config = config.get("DATABASE_CLIENT", {}).copy() if isinstance(config.get("DATABASE_CLIENT"), dict) else {}
|
|
189
|
+
|
|
190
|
+
# 支持环境变量覆盖
|
|
191
|
+
env_overrides = {
|
|
192
|
+
"base_url": os.getenv("DATABASE_CLIENT__base_url"),
|
|
193
|
+
"timeout": os.getenv("DATABASE_CLIENT__timeout"),
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
for key, value in env_overrides.items():
|
|
197
|
+
if value is not None:
|
|
198
|
+
db_config[key] = value
|
|
199
|
+
|
|
200
|
+
return db_config
|
|
201
|
+
|
|
202
|
+
def get_full_config(self) -> Dict[str, Any]:
|
|
203
|
+
"""
|
|
204
|
+
获取完整配置
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Dict[str, Any]: 完整配置字典
|
|
208
|
+
"""
|
|
209
|
+
return self.load_config()
|
|
210
|
+
|
|
211
|
+
def reload_config(self):
|
|
212
|
+
"""重新加载配置(清除缓存)"""
|
|
213
|
+
self._config_cache = None
|
|
214
|
+
logger.info("配置已重新加载")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# ============================================================================
|
|
218
|
+
# 全局默认配置管理器(向后兼容)
|
|
219
|
+
# ============================================================================
|
|
220
|
+
|
|
221
|
+
_default_config_manager: Optional[ConfigManager] = None
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _get_default_config_manager() -> ConfigManager:
|
|
225
|
+
"""获取默认配置管理器实例"""
|
|
226
|
+
global _default_config_manager
|
|
227
|
+
if _default_config_manager is None:
|
|
228
|
+
_default_config_manager = ConfigManager()
|
|
229
|
+
return _default_config_manager
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def set_config_manager(config_manager: ConfigManager):
|
|
233
|
+
"""
|
|
234
|
+
设置全局配置管理器(用于外部 SDK)
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
config_manager: ConfigManager 实例
|
|
238
|
+
|
|
239
|
+
Example:
|
|
240
|
+
# 在外部 SDK 中设置自定义配置
|
|
241
|
+
config_mgr = ConfigManager(config={...})
|
|
242
|
+
set_config_manager(config_mgr)
|
|
243
|
+
"""
|
|
244
|
+
global _default_config_manager
|
|
245
|
+
_default_config_manager = config_manager
|
|
246
|
+
logger.info("已设置全局配置管理器")
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# ============================================================================
|
|
250
|
+
# 向后兼容的函数接口
|
|
251
|
+
# ============================================================================
|
|
252
|
+
|
|
253
|
+
def load_config(force_reload: bool = False) -> Dict[str, Any]:
|
|
254
|
+
"""
|
|
255
|
+
加载配置文件(带缓存)
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
force_reload: 是否强制重新加载
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Dict[str, Any]: 完整配置字典
|
|
262
|
+
"""
|
|
263
|
+
return _get_default_config_manager().load_config(force_reload)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def get_llm_config(model_type: str = "BASIC_MODEL") -> Dict[str, Any]:
|
|
267
|
+
"""
|
|
268
|
+
获取LLM配置
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
model_type: 模型类型,可选 "BASIC_MODEL", "VISION_MODEL"
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
Dict[str, Any]: LLM配置
|
|
275
|
+
"""
|
|
276
|
+
return _get_default_config_manager().get_llm_config(model_type)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def get_rag_config() -> Dict[str, Any]:
|
|
280
|
+
"""
|
|
281
|
+
获取RAG客户端配置
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
Dict[str, Any]: RAG配置
|
|
285
|
+
"""
|
|
286
|
+
return _get_default_config_manager().get_rag_config()
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def get_database_config() -> Dict[str, Any]:
|
|
290
|
+
"""
|
|
291
|
+
获取数据库客户端配置
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
Dict[str, Any]: 数据库配置
|
|
295
|
+
"""
|
|
296
|
+
return _get_default_config_manager().get_database_config()
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def get_full_config() -> Dict[str, Any]:
|
|
300
|
+
"""
|
|
301
|
+
获取完整配置
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Dict[str, Any]: 完整配置字典
|
|
305
|
+
"""
|
|
306
|
+
return _get_default_config_manager().get_full_config()
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def reload_config():
|
|
310
|
+
"""重新加载配置(清除缓存)"""
|
|
311
|
+
_get_default_config_manager().reload_config()
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from dotenv import load_dotenv, find_dotenv
|
|
4
|
+
from langchain_openai import ChatOpenAI
|
|
5
|
+
|
|
6
|
+
load_dotenv(find_dotenv(usecwd=True))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
model_name = os.getenv("MODEL_NAME", None)
|
|
10
|
+
openai_api_base = os.getenv("OPENAI_API_BASE", None)
|
|
11
|
+
openai_api_key = os.getenv("OPENAI_API_KEY", 'API_KEY')
|
|
12
|
+
temperature = float(os.getenv("TEMPERATURE", 0.2))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def create_openai_llm(**kwargs):
|
|
16
|
+
_model_name = kwargs.pop('model_name', model_name)
|
|
17
|
+
_openai_api_base = kwargs.pop('openai_api_base', openai_api_base)
|
|
18
|
+
_openai_api_key = kwargs.pop('openai_api_key', openai_api_key)
|
|
19
|
+
if not _openai_api_key:
|
|
20
|
+
_openai_api_key = 'API_KEY'
|
|
21
|
+
_temperature = kwargs.pop('temperature', temperature)
|
|
22
|
+
|
|
23
|
+
assert model_name is not None
|
|
24
|
+
assert openai_api_base is not None
|
|
25
|
+
|
|
26
|
+
llm = ChatOpenAI(
|
|
27
|
+
model_name=_model_name,
|
|
28
|
+
openai_api_base=_openai_api_base,
|
|
29
|
+
openai_api_key=_openai_api_key,
|
|
30
|
+
temperature=_temperature,
|
|
31
|
+
**kwargs
|
|
32
|
+
)
|
|
33
|
+
return llm
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import re
|
|
3
|
+
from typing import Any, Dict, List, Union
|
|
4
|
+
|
|
5
|
+
from langchain_core.messages import BaseMessage, SystemMessage, HumanMessage
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def combine_simple_context(system: str, user: str = None):
|
|
9
|
+
context: List[Union[BaseMessage, dict[str, Any]]] = [SystemMessage(content=system)]
|
|
10
|
+
if user:
|
|
11
|
+
context.append(HumanMessage(content=system))
|
|
12
|
+
return context
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def fix_json_response(text: str) -> Union[Dict, List, str, int, float, bool, None]:
|
|
16
|
+
"""
|
|
17
|
+
去掉大模型返回的 ```json / ``` 等 markdown 标记,并安全反序列化 JSON。
|
|
18
|
+
若解析失败,返回原字符串。
|
|
19
|
+
|
|
20
|
+
参数
|
|
21
|
+
----
|
|
22
|
+
text : str
|
|
23
|
+
原始响应,可能包含 ```json ... ``` 或其他变体。
|
|
24
|
+
|
|
25
|
+
返回
|
|
26
|
+
----
|
|
27
|
+
Python 对象(dict / list / str / int / float / bool / None)
|
|
28
|
+
解析失败时返回输入字符串本身。
|
|
29
|
+
"""
|
|
30
|
+
if not isinstance(text, str):
|
|
31
|
+
return text
|
|
32
|
+
|
|
33
|
+
# 1. 去掉 ```json 或 ``` 包裹(支持开头、结尾、单行、多行)
|
|
34
|
+
cleaned = re.sub(r'^\s*```(?:json|JSON)?\s*\n?', '', text)
|
|
35
|
+
cleaned = re.sub(r'\n?\s*```\s*$', '', cleaned)
|
|
36
|
+
|
|
37
|
+
# 2. 去掉首尾空白
|
|
38
|
+
cleaned = cleaned.strip()
|
|
39
|
+
|
|
40
|
+
# 3. 尝试 JSON 反序列化
|
|
41
|
+
try:
|
|
42
|
+
json.loads(cleaned)
|
|
43
|
+
return cleaned
|
|
44
|
+
except json.JSONDecodeError:
|
|
45
|
+
# 4. 兜底:返回原字符串
|
|
46
|
+
return text
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ----------------- 使用示例 -----------------
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
demo_list = [
|
|
52
|
+
'```json\n{"a": 1, "b": "hello"}\n```',
|
|
53
|
+
"```JSON{'key': 'value'}```",
|
|
54
|
+
"```\n[1, 2, 3]```",
|
|
55
|
+
"plain text",
|
|
56
|
+
{"already_dict": 1},
|
|
57
|
+
]
|
|
58
|
+
for d in demo_list:
|
|
59
|
+
print("原始:", repr(d))
|
|
60
|
+
print("修复:", repr(fix_json_response(d)))
|
|
61
|
+
print("-" * 30)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import uuid
|
|
4
|
+
from logging.handlers import TimedRotatingFileHandler
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Union
|
|
7
|
+
|
|
8
|
+
from dotenv import load_dotenv, find_dotenv
|
|
9
|
+
|
|
10
|
+
load_dotenv(find_dotenv(usecwd=True))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
logger_root_path = os.getenv("LOGGER_ROOT_PATH", None)
|
|
14
|
+
log_dir = None
|
|
15
|
+
|
|
16
|
+
if logger_root_path:
|
|
17
|
+
if logger_root_path.endswith('/'):
|
|
18
|
+
log_dir = f"{logger_root_path}logs"
|
|
19
|
+
else:
|
|
20
|
+
log_dir = f"{logger_root_path}/logs"
|
|
21
|
+
Path(log_dir).mkdir(parents=True, exist_ok=True)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LogUtils:
|
|
25
|
+
_handlers = {}
|
|
26
|
+
|
|
27
|
+
# 日志文件根据日期创建
|
|
28
|
+
# 根据参数name,将message写入对应的日志文件内
|
|
29
|
+
@classmethod
|
|
30
|
+
def log(cls, name: str="log", message: str="", log_uuid: str = str(uuid.uuid4()), level: Union[int, str] = logging.INFO) -> None:
|
|
31
|
+
if not log_dir:
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
logger = logging.getLogger(name)
|
|
36
|
+
logger.setLevel(level)
|
|
37
|
+
logger.propagate = False
|
|
38
|
+
if name not in cls._handlers:
|
|
39
|
+
# 保证日志文件存在
|
|
40
|
+
# LOG_DIR.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
# print(f"Log directory created at: {LOG_DIR}")
|
|
42
|
+
handler = TimedRotatingFileHandler(f'{log_dir}/{name}.log', # 基础文件名
|
|
43
|
+
when='midnight', # 每天午夜
|
|
44
|
+
interval=1,
|
|
45
|
+
backupCount=7, # 保留7天
|
|
46
|
+
encoding='utf-8'
|
|
47
|
+
)
|
|
48
|
+
formatter = logging.Formatter('%(uuid)s - %(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
49
|
+
handler.setFormatter(formatter)
|
|
50
|
+
handler.setLevel(level)
|
|
51
|
+
|
|
52
|
+
# 控制台日志
|
|
53
|
+
stream_handler = logging.StreamHandler()
|
|
54
|
+
stream_handler.setLevel(level)
|
|
55
|
+
stream_formatter = logging.Formatter('%(uuid)s - %(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
56
|
+
stream_handler.setFormatter(stream_formatter)
|
|
57
|
+
if not logger.hasHandlers():
|
|
58
|
+
logger.addHandler(handler)
|
|
59
|
+
logger.addHandler(stream_handler)
|
|
60
|
+
cls._handlers[name] = handler
|
|
61
|
+
|
|
62
|
+
req_id = log_uuid or str(uuid.uuid4())
|
|
63
|
+
logger.log(level, message, extra={'uuid': req_id}) # 使用UUID
|
|
64
|
+
|
|
65
|
+
for handler in logger.handlers:
|
|
66
|
+
handler.flush()
|
|
67
|
+
except Exception as e:
|
|
68
|
+
# note: ignore error
|
|
69
|
+
pass
|