SimpleLLMFunc 0.2.0__tar.gz → 0.2.3__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.
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/PKG-INFO +4 -4
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/README.md +2 -3
- simplellmfunc-0.2.3/SimpleLLMFunc/.DS_Store +0 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/interface/llm_interface.py +16 -11
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/interface/openai_compatible.py +108 -58
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/llm_decorator/__init__.py +5 -3
- simplellmfunc-0.2.3/SimpleLLMFunc/llm_decorator/llm_chat_decorator.py +814 -0
- simplellmfunc-0.2.3/SimpleLLMFunc/llm_decorator/llm_function_decorator.py +1146 -0
- simplellmfunc-0.2.3/SimpleLLMFunc/llm_decorator/multimodal_types.py +110 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/llm_decorator/utils.py +171 -149
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/logger/__init__.py +2 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/logger/logger.py +151 -28
- simplellmfunc-0.2.3/SimpleLLMFunc/type/__init__.py +9 -0
- simplellmfunc-0.2.3/SimpleLLMFunc/utils.py +23 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/pyproject.toml +2 -1
- simplellmfunc-0.2.0/SimpleLLMFunc/llm_decorator/llm_chat_decorator.py +0 -331
- simplellmfunc-0.2.0/SimpleLLMFunc/llm_decorator/llm_function_decorator.py +0 -473
- simplellmfunc-0.2.0/SimpleLLMFunc/utils.py +0 -14
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/LICENSE +0 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/__init__.py +0 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/config.py +0 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/interface/__init__.py +0 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/interface/key_pool.py +0 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/logger/logger_config.py +0 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/tool/__init__.py +0 -0
- {simplellmfunc-0.2.0 → simplellmfunc-0.2.3}/SimpleLLMFunc/tool/tool.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: SimpleLLMFunc
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: 一个轻量但完备的LLM/Agent应用开发框架,提供装饰器实现将函数DocString作为Prompt而无需函数体具体实现但能够享受函数定义和类型标注带来效率提升的开发体验。以最Code的方式,用最少的代码将LLM能力集成到任意Python项目中。
|
|
5
5
|
Author: Ni Jingzhe
|
|
6
6
|
Author-email: nijingzhe@zjue.edu.cn
|
|
@@ -15,10 +15,10 @@ Requires-Dist: openai (>=1.84.0,<2.0.0)
|
|
|
15
15
|
Requires-Dist: pydantic (>=2.11.5,<3.0.0)
|
|
16
16
|
Requires-Dist: pydantic-settings (>=2.9.1,<3.0.0)
|
|
17
17
|
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
|
18
|
+
Requires-Dist: rich (>=14.0.0,<15.0.0)
|
|
18
19
|
Description-Content-Type: text/markdown
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-

|
|
21
|
+

|
|
22
22
|
|
|
23
23
|
<center>
|
|
24
24
|
<h2 style="font-size:2em;">Everything is Function, Prompt is Code</h2>
|
|
@@ -480,7 +480,7 @@ pip install SimpleLLMFunc
|
|
|
480
480
|
month = {June},
|
|
481
481
|
title = {{SimpleLLMFunc: A New Approach to Build LLM Applications}},
|
|
482
482
|
url = {https://github.com/NiJingzhe/SimpleLLMFunc},
|
|
483
|
-
version = {0.2.
|
|
483
|
+
version = {0.2.1},
|
|
484
484
|
year = {2025}
|
|
485
485
|
}
|
|
486
486
|
```
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-

|
|
1
|
+

|
|
3
2
|
|
|
4
3
|
<center>
|
|
5
4
|
<h2 style="font-size:2em;">Everything is Function, Prompt is Code</h2>
|
|
@@ -461,7 +460,7 @@ pip install SimpleLLMFunc
|
|
|
461
460
|
month = {June},
|
|
462
461
|
title = {{SimpleLLMFunc: A New Approach to Build LLM Applications}},
|
|
463
462
|
url = {https://github.com/NiJingzhe/SimpleLLMFunc},
|
|
464
|
-
version = {0.2.
|
|
463
|
+
version = {0.2.1},
|
|
465
464
|
year = {2025}
|
|
466
465
|
}
|
|
467
466
|
```
|
|
Binary file
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional, Dict, Iterable, Literal, Any, AsyncGenerator
|
|
3
3
|
|
|
4
4
|
from SimpleLLMFunc.interface.key_pool import APIKeyPool
|
|
5
5
|
from SimpleLLMFunc.logger import get_current_trace_id
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
class LLM_Interface(ABC):
|
|
8
|
-
|
|
9
|
+
|
|
9
10
|
@abstractmethod
|
|
10
|
-
def __init__(
|
|
11
|
+
def __init__(
|
|
12
|
+
self, api_key_pool: APIKeyPool, model_name: str, base_url: Optional[str] = None
|
|
13
|
+
):
|
|
11
14
|
self.input_token_count = 0
|
|
12
15
|
self.output_token_count = 0
|
|
13
|
-
|
|
16
|
+
|
|
14
17
|
@abstractmethod
|
|
15
|
-
def chat(
|
|
16
|
-
self,
|
|
18
|
+
async def chat(
|
|
19
|
+
self,
|
|
17
20
|
trace_id: str = get_current_trace_id(),
|
|
18
21
|
stream: Literal[False] = False,
|
|
19
22
|
messages: Iterable[Dict[str, str]] = [{"role": "user", "content": ""}],
|
|
@@ -22,15 +25,17 @@ class LLM_Interface(ABC):
|
|
|
22
25
|
**kwargs,
|
|
23
26
|
) -> Dict[Any, Any]:
|
|
24
27
|
pass
|
|
25
|
-
|
|
28
|
+
|
|
26
29
|
@abstractmethod
|
|
27
|
-
def chat_stream(
|
|
28
|
-
self,
|
|
30
|
+
async def chat_stream(
|
|
31
|
+
self,
|
|
29
32
|
trace_id: str = get_current_trace_id(),
|
|
30
33
|
stream: Literal[True] = True,
|
|
31
34
|
messages: Iterable[Dict[str, str]] = [{"role": "user", "content": ""}],
|
|
32
35
|
timeout: Optional[int] = None,
|
|
33
36
|
*args,
|
|
34
37
|
**kwargs,
|
|
35
|
-
) ->
|
|
36
|
-
|
|
38
|
+
) -> AsyncGenerator[Dict[Any, Any], None]:
|
|
39
|
+
# 空的异步生成器,永远不会产生任何值
|
|
40
|
+
if False:
|
|
41
|
+
yield {}
|
|
@@ -2,13 +2,25 @@ from __future__ import annotations
|
|
|
2
2
|
import json
|
|
3
3
|
import os
|
|
4
4
|
import time
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Optional, Dict, Literal, Iterable, Any, AsyncGenerator
|
|
6
6
|
|
|
7
|
-
from openai import
|
|
7
|
+
from openai import AsyncOpenAI
|
|
8
8
|
from SimpleLLMFunc.interface.llm_interface import LLM_Interface
|
|
9
9
|
from SimpleLLMFunc.interface.key_pool import APIKeyPool
|
|
10
|
-
from SimpleLLMFunc.logger import
|
|
11
|
-
|
|
10
|
+
from SimpleLLMFunc.logger import (
|
|
11
|
+
app_log,
|
|
12
|
+
push_warning,
|
|
13
|
+
push_error,
|
|
14
|
+
get_location,
|
|
15
|
+
get_current_trace_id,
|
|
16
|
+
push_debug,
|
|
17
|
+
)
|
|
18
|
+
from SimpleLLMFunc.logger.logger import (
|
|
19
|
+
push_critical,
|
|
20
|
+
get_current_context_attribute,
|
|
21
|
+
set_current_context_attribute,
|
|
22
|
+
)
|
|
23
|
+
|
|
12
24
|
|
|
13
25
|
class OpenAICompatible(LLM_Interface):
|
|
14
26
|
"""与OpenAI API兼容的LLM接口实现,支持任何符合OpenAI格式的API接口。
|
|
@@ -19,10 +31,10 @@ class OpenAICompatible(LLM_Interface):
|
|
|
19
31
|
|
|
20
32
|
def _count_tokens(self, response: Any) -> tuple[int, int]:
|
|
21
33
|
"""计算响应中的token数量
|
|
22
|
-
|
|
34
|
+
|
|
23
35
|
Args:
|
|
24
36
|
response: OpenAI API的响应对象
|
|
25
|
-
|
|
37
|
+
|
|
26
38
|
Returns:
|
|
27
39
|
(输入token数, 输出token数)的元组
|
|
28
40
|
"""
|
|
@@ -35,12 +47,14 @@ class OpenAICompatible(LLM_Interface):
|
|
|
35
47
|
return 0, 0
|
|
36
48
|
|
|
37
49
|
@classmethod
|
|
38
|
-
def load_from_json_file(
|
|
50
|
+
def load_from_json_file(
|
|
51
|
+
cls, json_path: str
|
|
52
|
+
) -> Dict[str, Dict[str, OpenAICompatible]]:
|
|
39
53
|
"""从JSON字符串加载OpenAICompatible实例
|
|
40
54
|
|
|
41
55
|
Args:
|
|
42
56
|
json_str: JSON字符串,包含API密钥和模型名称
|
|
43
|
-
|
|
57
|
+
|
|
44
58
|
例如:
|
|
45
59
|
```
|
|
46
60
|
{
|
|
@@ -75,25 +89,28 @@ class OpenAICompatible(LLM_Interface):
|
|
|
75
89
|
"max_retries": 5,
|
|
76
90
|
"retry_delay": 1.0
|
|
77
91
|
}
|
|
78
|
-
]
|
|
92
|
+
]
|
|
79
93
|
}
|
|
80
94
|
```
|
|
81
95
|
|
|
82
96
|
Returns:
|
|
83
|
-
OpenAICompatible实例的字典, 可以这样访问:
|
|
97
|
+
OpenAICompatible实例的字典, 可以这样访问:
|
|
84
98
|
```python
|
|
85
99
|
from SimpleLLMFunc.interface.openai_compatible import OpenAICompatible
|
|
86
100
|
|
|
87
101
|
all_models = OpenAICompatible.load_from_json(json_str)
|
|
88
102
|
gpt_3_5 = all_models["openai"]["gpt-3.5-turbo"]
|
|
89
103
|
gpt_4 = all_models["openai"]["gpt-4"]
|
|
90
|
-
```
|
|
104
|
+
```
|
|
91
105
|
"""
|
|
92
|
-
|
|
106
|
+
|
|
93
107
|
if not os.path.exists(json_path):
|
|
94
|
-
push_critical(
|
|
108
|
+
push_critical(
|
|
109
|
+
f"JSON 文件 {json_path} 不存在。请检查您的配置。",
|
|
110
|
+
location=get_location(),
|
|
111
|
+
)
|
|
95
112
|
raise FileNotFoundError(f"JSON 文件 {json_path} 不存在。")
|
|
96
|
-
|
|
113
|
+
|
|
97
114
|
with open(json_path, "r", encoding="utf-8") as f:
|
|
98
115
|
json_str = f.read()
|
|
99
116
|
# 解析JSON字符串
|
|
@@ -103,20 +120,25 @@ class OpenAICompatible(LLM_Interface):
|
|
|
103
120
|
push_critical(f"解析 JSON 字符串失败:{e}", location=get_location())
|
|
104
121
|
raise ValueError(f"解析 JSON 字符串失败:{e}")
|
|
105
122
|
# 检查JSON格式
|
|
106
|
-
|
|
107
|
-
try:
|
|
123
|
+
|
|
124
|
+
try:
|
|
108
125
|
all_providers_dict: Dict[str, Dict[str, OpenAICompatible]] = {}
|
|
109
126
|
for provider_id, models in all_providers_info.items():
|
|
110
127
|
all_providers_dict[provider_id] = {}
|
|
111
128
|
app_log(
|
|
112
129
|
f"正在为提供商加载 OpenAICompatible 实例:{provider_id}",
|
|
113
|
-
location=get_location()
|
|
130
|
+
location=get_location(),
|
|
114
131
|
)
|
|
115
|
-
|
|
132
|
+
|
|
116
133
|
if not isinstance(models, list):
|
|
117
|
-
push_critical(
|
|
118
|
-
|
|
119
|
-
|
|
134
|
+
push_critical(
|
|
135
|
+
f"提供商 {provider_id} 下的模型格式无效。应为列表。",
|
|
136
|
+
location=get_location(),
|
|
137
|
+
)
|
|
138
|
+
raise TypeError(
|
|
139
|
+
f"提供商 {provider_id} 下的模型格式无效。应为列表。"
|
|
140
|
+
)
|
|
141
|
+
|
|
120
142
|
for model_info in models:
|
|
121
143
|
model_name = model_info["model_name"]
|
|
122
144
|
api_keys = model_info["api_keys"]
|
|
@@ -137,13 +159,15 @@ class OpenAICompatible(LLM_Interface):
|
|
|
137
159
|
)
|
|
138
160
|
|
|
139
161
|
all_providers_dict[provider_id][model_name] = instance
|
|
140
|
-
|
|
162
|
+
|
|
141
163
|
app_log(
|
|
142
164
|
f"已为提供商 {provider_id} 加载模型 {model_name} 的 OpenAICompatible 实例",
|
|
143
|
-
location=get_location()
|
|
165
|
+
location=get_location(),
|
|
144
166
|
)
|
|
145
167
|
except ValueError as e:
|
|
146
|
-
push_critical(
|
|
168
|
+
push_critical(
|
|
169
|
+
f"加载 OpenAICompatible 实例时出错:{e}", location=get_location()
|
|
170
|
+
)
|
|
147
171
|
raise ValueError(f"加载 OpenAICompatible 实例时出错:{e}")
|
|
148
172
|
except TypeError as e:
|
|
149
173
|
push_critical(f"JSON 中的类型无效:{e}", location=get_location())
|
|
@@ -152,14 +176,19 @@ class OpenAICompatible(LLM_Interface):
|
|
|
152
176
|
push_critical(f"JSON 中缺少必需的密钥:{e}", location=get_location())
|
|
153
177
|
raise ValueError(f"JSON 中缺少必需的密钥:{e}")
|
|
154
178
|
except Exception as e:
|
|
155
|
-
push_critical(
|
|
179
|
+
push_critical(
|
|
180
|
+
f"加载 OpenAICompatible 实例时发生未知错误:{e}",
|
|
181
|
+
location=get_location(),
|
|
182
|
+
)
|
|
156
183
|
raise ValueError(f"加载 OpenAICompatible 实例时发生未知错误:{e}")
|
|
157
|
-
|
|
184
|
+
|
|
158
185
|
return all_providers_dict
|
|
159
186
|
|
|
160
187
|
def __repr__(self) -> str:
|
|
161
188
|
"""返回OpenAICompatible实例的字符串表示"""
|
|
162
|
-
return
|
|
189
|
+
return (
|
|
190
|
+
f"OpenAICompatible(model_name={self.model_name}, base_url={self.base_url})"
|
|
191
|
+
)
|
|
163
192
|
|
|
164
193
|
def __init__(
|
|
165
194
|
self,
|
|
@@ -186,13 +215,20 @@ class OpenAICompatible(LLM_Interface):
|
|
|
186
215
|
self.model_name = model_name
|
|
187
216
|
|
|
188
217
|
self.key_pool = api_key_pool
|
|
189
|
-
self.client =
|
|
218
|
+
self.client = AsyncOpenAI(
|
|
219
|
+
api_key=api_key_pool.get_least_loaded_key(), base_url=self.base_url
|
|
220
|
+
)
|
|
190
221
|
|
|
191
|
-
def chat(
|
|
222
|
+
async def chat(
|
|
192
223
|
self,
|
|
193
224
|
trace_id: str = get_current_trace_id(),
|
|
194
225
|
stream: Literal[False] = False,
|
|
195
|
-
messages: Iterable[Dict[str, str]] = [
|
|
226
|
+
messages: Iterable[Dict[str, str]] = [
|
|
227
|
+
{
|
|
228
|
+
"role": "system",
|
|
229
|
+
"content": "你是一位乐于助人的助手,可以帮助用户解决各种问题。",
|
|
230
|
+
}
|
|
231
|
+
],
|
|
196
232
|
timeout: Optional[int] = 30,
|
|
197
233
|
*args,
|
|
198
234
|
**kwargs,
|
|
@@ -210,19 +246,19 @@ class OpenAICompatible(LLM_Interface):
|
|
|
210
246
|
LLM的响应内容
|
|
211
247
|
"""
|
|
212
248
|
key = self.key_pool.get_least_loaded_key()
|
|
213
|
-
self.client =
|
|
214
|
-
|
|
249
|
+
self.client = AsyncOpenAI(api_key=key, base_url=self.base_url)
|
|
250
|
+
|
|
215
251
|
attempt = 0
|
|
216
252
|
while attempt < self.max_retries:
|
|
217
253
|
try:
|
|
218
254
|
self.key_pool.increment_task_count(key)
|
|
219
255
|
data = json.dumps(messages, ensure_ascii=False, indent=4)
|
|
220
|
-
|
|
256
|
+
push_debug(
|
|
221
257
|
f"OpenAICompatible::chat: {self.model_name} request with API key: {key}, and message: {data}",
|
|
222
|
-
location=get_location()
|
|
258
|
+
location=get_location(),
|
|
223
259
|
)
|
|
224
|
-
response: Dict[Any, Any] = self.client.chat.completions.create( # type: ignore
|
|
225
|
-
messages=messages,
|
|
260
|
+
response: Dict[Any, Any] = await self.client.chat.completions.create( # type: ignore
|
|
261
|
+
messages=messages, # type: ignore
|
|
226
262
|
model=self.model_name,
|
|
227
263
|
stream=stream,
|
|
228
264
|
timeout=timeout,
|
|
@@ -233,17 +269,21 @@ class OpenAICompatible(LLM_Interface):
|
|
|
233
269
|
# 统计token
|
|
234
270
|
if not (response.choices and response.choices[0].message and response.choices[0].message.tool_calls): # type: ignore
|
|
235
271
|
prompt_tokens, completion_tokens = self._count_tokens(response)
|
|
236
|
-
|
|
272
|
+
|
|
237
273
|
# 更新上下文中的token计数
|
|
238
274
|
input_tokens = get_current_context_attribute("input_tokens") or 0
|
|
239
275
|
output_tokens = get_current_context_attribute("output_tokens") or 0
|
|
240
|
-
|
|
241
|
-
set_current_context_attribute(
|
|
242
|
-
|
|
243
|
-
|
|
276
|
+
|
|
277
|
+
set_current_context_attribute(
|
|
278
|
+
"input_tokens", input_tokens + prompt_tokens
|
|
279
|
+
)
|
|
280
|
+
set_current_context_attribute(
|
|
281
|
+
"output_tokens", output_tokens + completion_tokens
|
|
282
|
+
)
|
|
283
|
+
|
|
244
284
|
self.key_pool.decrement_task_count(key)
|
|
245
285
|
return response # 请求成功,返回结果
|
|
246
|
-
|
|
286
|
+
|
|
247
287
|
except Exception as e:
|
|
248
288
|
self.key_pool.decrement_task_count(key)
|
|
249
289
|
attempt += 1
|
|
@@ -255,7 +295,7 @@ class OpenAICompatible(LLM_Interface):
|
|
|
255
295
|
)
|
|
256
296
|
|
|
257
297
|
key = self.key_pool.get_least_loaded_key()
|
|
258
|
-
self.client =
|
|
298
|
+
self.client = AsyncOpenAI(api_key=key, base_url=self.base_url)
|
|
259
299
|
|
|
260
300
|
if attempt >= self.max_retries:
|
|
261
301
|
push_error(
|
|
@@ -266,15 +306,20 @@ class OpenAICompatible(LLM_Interface):
|
|
|
266
306
|
time.sleep(self.retry_delay) # 重试前等待一段时间
|
|
267
307
|
return {} # 添加默认返回以满足类型检查,实际上这行代码永远不会执行
|
|
268
308
|
|
|
269
|
-
def chat_stream(
|
|
309
|
+
async def chat_stream(
|
|
270
310
|
self,
|
|
271
311
|
trace_id: str = get_current_trace_id(),
|
|
272
312
|
stream: Literal[True] = True,
|
|
273
|
-
messages: Iterable[Dict[str, str]] = [
|
|
313
|
+
messages: Iterable[Dict[str, str]] = [
|
|
314
|
+
{
|
|
315
|
+
"role": "system",
|
|
316
|
+
"content": "你是一位乐于助人的助手,可以帮助用户解决各种问题。",
|
|
317
|
+
}
|
|
318
|
+
],
|
|
274
319
|
timeout: Optional[int] = 30,
|
|
275
320
|
*args,
|
|
276
321
|
**kwargs,
|
|
277
|
-
) ->
|
|
322
|
+
) -> AsyncGenerator[Dict[Any, Any], None]:
|
|
278
323
|
"""执行流式LLM对话请求
|
|
279
324
|
|
|
280
325
|
Args:
|
|
@@ -288,18 +333,18 @@ class OpenAICompatible(LLM_Interface):
|
|
|
288
333
|
LLM的响应块
|
|
289
334
|
"""
|
|
290
335
|
key = self.key_pool.get_least_loaded_key()
|
|
291
|
-
self.client =
|
|
336
|
+
self.client = AsyncOpenAI(api_key=key, base_url=self.base_url)
|
|
292
337
|
|
|
293
338
|
attempt = 0
|
|
294
339
|
while attempt < self.max_retries:
|
|
295
340
|
try:
|
|
296
341
|
self.key_pool.increment_task_count(key)
|
|
297
342
|
data = json.dumps(messages, ensure_ascii=False, indent=4)
|
|
298
|
-
|
|
343
|
+
push_debug(
|
|
299
344
|
f"OpenAICompatible::chat_stream: {self.model_name} request with API key: {key}, and message: {data}",
|
|
300
|
-
location=get_location()
|
|
345
|
+
location=get_location(),
|
|
301
346
|
)
|
|
302
|
-
response
|
|
347
|
+
response = await self.client.chat.completions.create( # type: ignore
|
|
303
348
|
messages=messages, # type: ignore
|
|
304
349
|
model=self.model_name,
|
|
305
350
|
stream=stream,
|
|
@@ -311,7 +356,7 @@ class OpenAICompatible(LLM_Interface):
|
|
|
311
356
|
total_prompt_tokens = 0
|
|
312
357
|
total_completion_tokens = 0
|
|
313
358
|
|
|
314
|
-
for chunk in response:
|
|
359
|
+
async for chunk in response:
|
|
315
360
|
yield chunk # 按块返回生成器中的数据
|
|
316
361
|
if chunk.choices and chunk.choices[0].delta: # type: ignore
|
|
317
362
|
if not chunk.choices[0].delta.tool_calls: # type: ignore
|
|
@@ -323,8 +368,12 @@ class OpenAICompatible(LLM_Interface):
|
|
|
323
368
|
input_tokens = get_current_context_attribute("input_tokens") or 0
|
|
324
369
|
output_tokens = get_current_context_attribute("output_tokens") or 0
|
|
325
370
|
|
|
326
|
-
set_current_context_attribute(
|
|
327
|
-
|
|
371
|
+
set_current_context_attribute(
|
|
372
|
+
"input_tokens", input_tokens + total_prompt_tokens
|
|
373
|
+
)
|
|
374
|
+
set_current_context_attribute(
|
|
375
|
+
"output_tokens", output_tokens + total_completion_tokens
|
|
376
|
+
)
|
|
328
377
|
|
|
329
378
|
self.key_pool.decrement_task_count(key)
|
|
330
379
|
break # 如果成功,跳出重试循环
|
|
@@ -335,20 +384,21 @@ class OpenAICompatible(LLM_Interface):
|
|
|
335
384
|
data = json.dumps(messages, ensure_ascii=False, indent=4)
|
|
336
385
|
push_warning(
|
|
337
386
|
f"{self.model_name} Interface attempt {attempt} failed: With message : {data} send, \n but exception : {str(e)} was caught",
|
|
338
|
-
location=get_location()
|
|
387
|
+
location=get_location(),
|
|
339
388
|
)
|
|
340
389
|
|
|
341
390
|
key = self.key_pool.get_least_loaded_key()
|
|
342
|
-
self.client =
|
|
391
|
+
self.client = AsyncOpenAI(api_key=key, base_url=self.base_url)
|
|
343
392
|
|
|
344
393
|
if attempt >= self.max_retries:
|
|
345
394
|
push_error(
|
|
346
395
|
f"Max retries reached. {self.model_name} Failed to get a response for {data}",
|
|
347
|
-
location=get_location()
|
|
396
|
+
location=get_location(),
|
|
348
397
|
)
|
|
349
398
|
raise e
|
|
350
399
|
time.sleep(self.retry_delay)
|
|
351
|
-
|
|
400
|
+
|
|
352
401
|
# 下面是一个空生成器,用于满足类型检查,实际上永远不会执行到这里
|
|
353
402
|
if False:
|
|
354
|
-
yield {}
|
|
403
|
+
yield {}
|
|
404
|
+
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
from SimpleLLMFunc.llm_decorator.llm_function_decorator import llm_function
|
|
2
|
-
from SimpleLLMFunc.llm_decorator.llm_chat_decorator import llm_chat
|
|
1
|
+
from SimpleLLMFunc.llm_decorator.llm_function_decorator import llm_function, async_llm_function
|
|
2
|
+
from SimpleLLMFunc.llm_decorator.llm_chat_decorator import llm_chat, async_llm_chat
|
|
3
3
|
__all__ = [
|
|
4
4
|
"llm_function",
|
|
5
|
-
"
|
|
5
|
+
"async_llm_function",
|
|
6
|
+
"llm_chat",
|
|
7
|
+
"async_llm_chat"
|
|
6
8
|
]
|