aient 1.0.44__py3-none-any.whl → 1.0.46__py3-none-any.whl
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.
- aient/core/models.py +4 -0
- aient/core/request.py +26 -10
- aient/core/response.py +0 -2
- aient/core/utils.py +32 -4
- aient/models/chatgpt.py +6 -1
- {aient-1.0.44.dist-info → aient-1.0.46.dist-info}/METADATA +1 -1
- {aient-1.0.44.dist-info → aient-1.0.46.dist-info}/RECORD +10 -10
- {aient-1.0.44.dist-info → aient-1.0.46.dist-info}/WHEEL +0 -0
- {aient-1.0.44.dist-info → aient-1.0.46.dist-info}/licenses/LICENSE +0 -0
- {aient-1.0.44.dist-info → aient-1.0.46.dist-info}/top_level.txt +0 -0
aient/core/models.py
CHANGED
@@ -86,6 +86,9 @@ class Thinking(BaseModel):
|
|
86
86
|
budget_tokens: Optional[int] = None
|
87
87
|
type: Optional[Literal["enabled", "disabled"]] = None
|
88
88
|
|
89
|
+
class StreamOptions(BaseModel):
|
90
|
+
include_usage: Optional[bool] = None
|
91
|
+
|
89
92
|
class RequestModel(BaseRequest):
|
90
93
|
model: str
|
91
94
|
messages: List[Message]
|
@@ -105,6 +108,7 @@ class RequestModel(BaseRequest):
|
|
105
108
|
tools: Optional[List[Tool]] = None
|
106
109
|
response_format: Optional[ResponseFormat] = None
|
107
110
|
thinking: Optional[Thinking] = None
|
111
|
+
stream_options: Optional[StreamOptions] = None
|
108
112
|
|
109
113
|
def get_last_text_message(self) -> Optional[str]:
|
110
114
|
for message in reversed(self.messages):
|
aient/core/request.py
CHANGED
@@ -96,7 +96,8 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
|
|
96
96
|
content[0]["text"] = re.sub(r"_+", "_", content[0]["text"])
|
97
97
|
systemInstruction = {"parts": content}
|
98
98
|
|
99
|
-
|
99
|
+
off_models = ["gemini-2.0-flash-exp", "gemini-1.5", "gemini-2.5-pro"]
|
100
|
+
if any(off_model in original_model for off_model in off_models):
|
100
101
|
safety_settings = "OFF"
|
101
102
|
else:
|
102
103
|
safety_settings = "BLOCK_NONE"
|
@@ -119,7 +120,11 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
|
|
119
120
|
{
|
120
121
|
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
|
121
122
|
"threshold": safety_settings
|
122
|
-
}
|
123
|
+
},
|
124
|
+
{
|
125
|
+
"category": "HARM_CATEGORY_CIVIC_INTEGRITY",
|
126
|
+
"threshold": "BLOCK_NONE"
|
127
|
+
},
|
123
128
|
]
|
124
129
|
}
|
125
130
|
|
@@ -144,7 +149,8 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
|
|
144
149
|
'include_usage',
|
145
150
|
'logprobs',
|
146
151
|
'top_logprobs',
|
147
|
-
'response_format'
|
152
|
+
'response_format',
|
153
|
+
'stream_options',
|
148
154
|
]
|
149
155
|
generation_config = {}
|
150
156
|
|
@@ -190,9 +196,12 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
|
|
190
196
|
else:
|
191
197
|
payload[field] = value
|
192
198
|
|
193
|
-
|
194
|
-
|
195
|
-
|
199
|
+
max_token_65k_models = ["gemini-2.5-pro", "gemini-2.0-pro", "gemini-2.0-flash-thinking"]
|
200
|
+
payload["generationConfig"] = generation_config
|
201
|
+
if "maxOutputTokens" not in generation_config:
|
202
|
+
if any(pro_model in original_model for pro_model in max_token_65k_models):
|
203
|
+
payload["generationConfig"]["maxOutputTokens"] = 65536
|
204
|
+
else:
|
196
205
|
payload["generationConfig"]["maxOutputTokens"] = 8192
|
197
206
|
|
198
207
|
if request.model.endswith("-search"):
|
@@ -277,7 +286,8 @@ async def get_vertex_gemini_payload(request, engine, provider, api_key=None):
|
|
277
286
|
original_model = model_dict[request.model]
|
278
287
|
search_tool = None
|
279
288
|
|
280
|
-
|
289
|
+
pro_models = ["gemini-2.5-pro", "gemini-2.0-pro", "gemini-exp"]
|
290
|
+
if any(pro_model in original_model for pro_model in pro_models):
|
281
291
|
location = gemini2
|
282
292
|
search_tool = {"googleSearch": {}}
|
283
293
|
else:
|
@@ -384,7 +394,8 @@ async def get_vertex_gemini_payload(request, engine, provider, api_key=None):
|
|
384
394
|
'user',
|
385
395
|
'include_usage',
|
386
396
|
'logprobs',
|
387
|
-
'top_logprobs'
|
397
|
+
'top_logprobs',
|
398
|
+
'stream_options',
|
388
399
|
]
|
389
400
|
generation_config = {}
|
390
401
|
|
@@ -549,6 +560,7 @@ async def get_vertex_claude_payload(request, engine, provider, api_key=None):
|
|
549
560
|
'n',
|
550
561
|
'user',
|
551
562
|
'include_usage',
|
563
|
+
'stream_options',
|
552
564
|
]
|
553
565
|
|
554
566
|
for field, value in request.model_dump(exclude_unset=True).items():
|
@@ -845,6 +857,7 @@ async def get_openrouter_payload(request, engine, provider, api_key=None):
|
|
845
857
|
'n',
|
846
858
|
'user',
|
847
859
|
'include_usage',
|
860
|
+
'stream_options',
|
848
861
|
]
|
849
862
|
|
850
863
|
for field, value in request.model_dump(exclude_unset=True).items():
|
@@ -912,7 +925,8 @@ async def get_cohere_payload(request, engine, provider, api_key=None):
|
|
912
925
|
'user',
|
913
926
|
'include_usage',
|
914
927
|
'logprobs',
|
915
|
-
'top_logprobs'
|
928
|
+
'top_logprobs',
|
929
|
+
'stream_options',
|
916
930
|
]
|
917
931
|
|
918
932
|
for field, value in request.model_dump(exclude_unset=True).items():
|
@@ -959,7 +973,8 @@ async def get_cloudflare_payload(request, engine, provider, api_key=None):
|
|
959
973
|
'user',
|
960
974
|
'include_usage',
|
961
975
|
'logprobs',
|
962
|
-
'top_logprobs'
|
976
|
+
'top_logprobs',
|
977
|
+
'stream_options',
|
963
978
|
]
|
964
979
|
|
965
980
|
for field, value in request.model_dump(exclude_unset=True).items():
|
@@ -1141,6 +1156,7 @@ async def get_claude_payload(request, engine, provider, api_key=None):
|
|
1141
1156
|
'n',
|
1142
1157
|
'user',
|
1143
1158
|
'include_usage',
|
1159
|
+
'stream_options',
|
1144
1160
|
]
|
1145
1161
|
|
1146
1162
|
for field, value in request.model_dump(exclude_unset=True).items():
|
aient/core/response.py
CHANGED
@@ -50,7 +50,6 @@ async def fetch_gemini_response_stream(client, url, headers, payload, model):
|
|
50
50
|
try:
|
51
51
|
json_data = json.loads( "{" + line + "}")
|
52
52
|
content = json_data.get('text', '')
|
53
|
-
content = "\n".join(content.split("\\n"))
|
54
53
|
# content = content.replace("\n", "\n\n")
|
55
54
|
# if last_text_line == 0 and is_thinking:
|
56
55
|
# content = "> " + content.lstrip()
|
@@ -108,7 +107,6 @@ async def fetch_vertex_claude_response_stream(client, url, headers, payload, mod
|
|
108
107
|
try:
|
109
108
|
json_data = json.loads( "{" + line + "}")
|
110
109
|
content = json_data.get('text', '')
|
111
|
-
content = "\n".join(content.split("\\n"))
|
112
110
|
sse_string = await generate_sse_response(timestamp, model, content=content)
|
113
111
|
yield sse_string
|
114
112
|
except json.JSONDecodeError:
|
aient/core/utils.py
CHANGED
@@ -155,7 +155,8 @@ def update_initial_model(provider):
|
|
155
155
|
proxy = safe_get(provider, "preferences", "proxy", default=None)
|
156
156
|
client_config = get_proxy(proxy)
|
157
157
|
if engine == "gemini":
|
158
|
-
|
158
|
+
before_v1 = api_url.split("/v1beta")[0]
|
159
|
+
url = before_v1 + "/v1beta/models"
|
159
160
|
params = {"key": api}
|
160
161
|
with httpx.Client(**client_config) as client:
|
161
162
|
response = client.get(url, params=params)
|
@@ -288,7 +289,7 @@ class ThreadSafeCircularList:
|
|
288
289
|
# self.requests[item] = []
|
289
290
|
logger.warning(f"API key {item} 已进入冷却状态,冷却时间 {cooling_time} 秒")
|
290
291
|
|
291
|
-
async def is_rate_limited(self, item, model: str = None) -> bool:
|
292
|
+
async def is_rate_limited(self, item, model: str = None, is_check: bool = False) -> bool:
|
292
293
|
now = time()
|
293
294
|
# 检查是否在冷却中
|
294
295
|
if now < self.cooling_until[item]:
|
@@ -321,7 +322,8 @@ class ThreadSafeCircularList:
|
|
321
322
|
# 使用特定模型的请求记录进行计算
|
322
323
|
recent_requests = sum(1 for req in self.requests[item][model_key] if req > now - limit_period)
|
323
324
|
if recent_requests >= limit_count:
|
324
|
-
|
325
|
+
if not is_check:
|
326
|
+
logger.warning(f"API key {item}: model: {model_key} has been rate limited ({limit_count}/{limit_period} seconds)")
|
325
327
|
return True
|
326
328
|
|
327
329
|
# 清理太旧的请求记录
|
@@ -329,7 +331,9 @@ class ThreadSafeCircularList:
|
|
329
331
|
self.requests[item][model_key] = [req for req in self.requests[item][model_key] if req > now - max_period]
|
330
332
|
|
331
333
|
# 记录新的请求
|
332
|
-
|
334
|
+
if not is_check:
|
335
|
+
self.requests[item][model_key].append(now)
|
336
|
+
|
333
337
|
return False
|
334
338
|
|
335
339
|
async def next(self, model: str = None):
|
@@ -349,6 +353,30 @@ class ThreadSafeCircularList:
|
|
349
353
|
logger.warning(f"All API keys are rate limited!")
|
350
354
|
raise HTTPException(status_code=429, detail="Too many requests")
|
351
355
|
|
356
|
+
async def is_all_rate_limited(self, model: str = None) -> bool:
|
357
|
+
"""检查是否所有的items都被速率限制
|
358
|
+
|
359
|
+
与next方法不同,此方法不会改变任何内部状态(如self.index),
|
360
|
+
仅返回一个布尔值表示是否所有的key都被限制。
|
361
|
+
|
362
|
+
Args:
|
363
|
+
model: 要检查的模型名称,默认为None
|
364
|
+
|
365
|
+
Returns:
|
366
|
+
bool: 如果所有items都被速率限制返回True,否则返回False
|
367
|
+
"""
|
368
|
+
if len(self.items) == 0:
|
369
|
+
return False
|
370
|
+
|
371
|
+
async with self.lock:
|
372
|
+
for item in self.items:
|
373
|
+
if not await self.is_rate_limited(item, model, is_check=True):
|
374
|
+
return False
|
375
|
+
|
376
|
+
# 如果遍历完所有items都被限制,返回True
|
377
|
+
# logger.debug(f"Check result: all items are rate limited!")
|
378
|
+
return True
|
379
|
+
|
352
380
|
async def after_next_current(self):
|
353
381
|
# 返回当前取出的 API,因为已经调用了 next,所以当前API应该是上一个
|
354
382
|
if len(self.items) == 0:
|
aient/models/chatgpt.py
CHANGED
@@ -159,7 +159,9 @@ class chatgpt(BaseLLM):
|
|
159
159
|
|
160
160
|
conversation_len = len(self.conversation[convo_id]) - 1
|
161
161
|
message_index = 0
|
162
|
-
#
|
162
|
+
# if self.print_log:
|
163
|
+
# replaced_text = json.loads(re.sub(r';base64,([A-Za-z0-9+/=]+)', ';base64,***', json.dumps(self.conversation[convo_id])))
|
164
|
+
# print(json.dumps(replaced_text, indent=4, ensure_ascii=False))
|
163
165
|
while message_index < conversation_len:
|
164
166
|
if self.conversation[convo_id][message_index]["role"] == self.conversation[convo_id][message_index + 1]["role"]:
|
165
167
|
if self.conversation[convo_id][message_index].get("content") and self.conversation[convo_id][message_index + 1].get("content"):
|
@@ -180,6 +182,9 @@ class chatgpt(BaseLLM):
|
|
180
182
|
and type(self.conversation[convo_id][message_index + 1]["content"]) == dict:
|
181
183
|
self.conversation[convo_id][message_index]["content"] = [self.conversation[convo_id][message_index]["content"]]
|
182
184
|
self.conversation[convo_id][message_index + 1]["content"] = [self.conversation[convo_id][message_index + 1]["content"]]
|
185
|
+
if type(self.conversation[convo_id][message_index]["content"]) == list \
|
186
|
+
and type(self.conversation[convo_id][message_index + 1]["content"]) == dict:
|
187
|
+
self.conversation[convo_id][message_index + 1]["content"] = [self.conversation[convo_id][message_index + 1]["content"]]
|
183
188
|
self.conversation[convo_id][message_index]["content"] += self.conversation[convo_id][message_index + 1]["content"]
|
184
189
|
self.conversation[convo_id].pop(message_index + 1)
|
185
190
|
conversation_len = conversation_len - 1
|
@@ -2,17 +2,17 @@ aient/__init__.py,sha256=SRfF7oDVlOOAi6nGKiJIUK6B_arqYLO9iSMp-2IZZps,21
|
|
2
2
|
aient/core/.git,sha256=lrAcW1SxzRBUcUiuKL5tS9ykDmmTXxyLP3YYU-Y-Q-I,45
|
3
3
|
aient/core/__init__.py,sha256=NxjebTlku35S4Dzr16rdSqSTWUvvwEeACe8KvHJnjPg,34
|
4
4
|
aient/core/log_config.py,sha256=kz2_yJv1p-o3lUQOwA3qh-LSc3wMHv13iCQclw44W9c,274
|
5
|
-
aient/core/models.py,sha256=
|
6
|
-
aient/core/request.py,sha256
|
7
|
-
aient/core/response.py,sha256=
|
8
|
-
aient/core/utils.py,sha256=
|
5
|
+
aient/core/models.py,sha256=H3_XuWA7aS25MWZPK1c-5RBiiuxWJbTfE3RAk0Pkc9A,7504
|
6
|
+
aient/core/request.py,sha256=OlMkjGMcFAH-ItA1PgPuf2HT-RbI-Ca4JXncWApc3gM,49088
|
7
|
+
aient/core/response.py,sha256=7RVSFfGHisejv2SlsHvp0t-N_8OpTS4edQU_NOi5BGU,25822
|
8
|
+
aient/core/utils.py,sha256=I0u3WLWaMd4j1ShqKg_tz67m-1wr_uXlWgxGeUjIIiE,25098
|
9
9
|
aient/core/test/test_base_api.py,sha256=CjfFzMG26r8C4xCPoVkKb3Ac6pp9gy5NUCbZJHoSSsM,393
|
10
10
|
aient/core/test/test_image.py,sha256=_T4peNGdXKBHHxyQNx12u-NTyFE8TlYI6NvvagsG2LE,319
|
11
11
|
aient/core/test/test_payload.py,sha256=8jBiJY1uidm1jzL-EiK0s6UGmW9XkdsuuKFGrwFhFkw,2755
|
12
12
|
aient/models/__init__.py,sha256=ouNDNvoBBpIFrLsk09Q_sq23HR0GbLAKfGLIFmfEuXE,219
|
13
13
|
aient/models/audio.py,sha256=kRd-8-WXzv4vwvsTGwnstK-WR8--vr9CdfCZzu8y9LA,1934
|
14
14
|
aient/models/base.py,sha256=Loyt2F2WrDMBbK-sdmTtgkLVtdUXxK5tg4qoI6nc0Xo,7527
|
15
|
-
aient/models/chatgpt.py,sha256=
|
15
|
+
aient/models/chatgpt.py,sha256=QGMx2szrYlK-uqe18Vbem3ou37nrQFhS7vonpLxHrUo,42173
|
16
16
|
aient/models/claude.py,sha256=thK9P8qkaaoUN3OOJ9Shw4KDs-pAGKPoX4FOPGFXva8,28597
|
17
17
|
aient/models/duckduckgo.py,sha256=1l7vYCs9SG5SWPCbcl7q6pCcB5AUF_r-a4l9frz3Ogo,8115
|
18
18
|
aient/models/gemini.py,sha256=chGLc-8G_DAOxr10HPoOhvVFW1RvMgHd6mt--VyAW98,14730
|
@@ -29,8 +29,8 @@ aient/plugins/websearch.py,sha256=yiBzqXK5X220ibR-zko3VDsn4QOnLu1k6E2YOygCeTQ,15
|
|
29
29
|
aient/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
30
|
aient/utils/prompt.py,sha256=UcSzKkFE4-h_1b6NofI6xgk3GoleqALRKY8VBaXLjmI,11311
|
31
31
|
aient/utils/scripts.py,sha256=obrf5oxzFQPCu1A5MYDDiZv_LM6l9C1QSkgWIqcu28k,25690
|
32
|
-
aient-1.0.
|
33
|
-
aient-1.0.
|
34
|
-
aient-1.0.
|
35
|
-
aient-1.0.
|
36
|
-
aient-1.0.
|
32
|
+
aient-1.0.46.dist-info/licenses/LICENSE,sha256=XNdbcWldt0yaNXXWB_Bakoqnxb3OVhUft4MgMA_71ds,1051
|
33
|
+
aient-1.0.46.dist-info/METADATA,sha256=nYfiefitlFshZCNddR3PTfypDm1mrCtJhjboAJmoNOQ,4986
|
34
|
+
aient-1.0.46.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
35
|
+
aient-1.0.46.dist-info/top_level.txt,sha256=3oXzrP5sAVvyyqabpeq8A2_vfMtY554r4bVE-OHBrZk,6
|
36
|
+
aient-1.0.46.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|