MeUtils 2025.9.3.23.13.47__py3-none-any.whl → 2025.9.7.0.7.25__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.
- examples/_openaisdk/openai_router.py +24 -14
- meutils/apis/google/chat.py +12 -9
- meutils/apis/google/images.py +33 -19
- meutils/apis/images/generations.py +7 -6
- meutils/apis/jimeng/images.py +1 -0
- meutils/apis/volcengine_apis/videos.py +5 -4
- meutils/data/VERSION +1 -1
- meutils/io/files_utils.py +17 -2
- meutils/llm/check_utils.py +5 -9
- meutils/llm/completions/qwenllm.py +13 -40
- meutils/llm/models/modelscope.py +20 -1
- meutils/llm/models/openrouter.py +3 -30
- meutils/llm/models/siliconflow.py +3 -2
- meutils/llm/openai_utils/adapters.py +45 -30
- meutils/schemas/oneapi/_types.py +9 -2
- meutils/schemas/oneapi/common.py +11 -0
- meutils/str_utils/__init__.py +1 -1
- meutils/str_utils/regular_expression.py +17 -2
- {meutils-2025.9.3.23.13.47.dist-info → meutils-2025.9.7.0.7.25.dist-info}/METADATA +262 -262
- {meutils-2025.9.3.23.13.47.dist-info → meutils-2025.9.7.0.7.25.dist-info}/RECORD +24 -24
- {meutils-2025.9.3.23.13.47.dist-info → meutils-2025.9.7.0.7.25.dist-info}/WHEEL +0 -0
- {meutils-2025.9.3.23.13.47.dist-info → meutils-2025.9.7.0.7.25.dist-info}/entry_points.txt +0 -0
- {meutils-2025.9.3.23.13.47.dist-info → meutils-2025.9.7.0.7.25.dist-info}/licenses/LICENSE +0 -0
- {meutils-2025.9.3.23.13.47.dist-info → meutils-2025.9.7.0.7.25.dist-info}/top_level.txt +0 -0
@@ -33,26 +33,6 @@ async def chat_for_image(
|
|
33
33
|
):
|
34
34
|
generate = generate and partial(generate, api_key=api_key, base_url=base_url)
|
35
35
|
|
36
|
-
if not request.stream or request.last_user_content.startswith( # 跳过nextchat
|
37
|
-
(
|
38
|
-
"hi",
|
39
|
-
"使用四到五个字直接返回这句话的简要主题",
|
40
|
-
"简要总结一下对话内容,用作后续的上下文提示 prompt,控制在 200 字以内"
|
41
|
-
)):
|
42
|
-
chat_completion.choices[0].message.content = "请设置`stream=True`"
|
43
|
-
return chat_completion
|
44
|
-
|
45
|
-
# request.stream = True # 流转非流
|
46
|
-
# response = await chat_for_image(generate, request, api_key)
|
47
|
-
# chunks = await stream.list(response)
|
48
|
-
#
|
49
|
-
# logger.debug(chunks)
|
50
|
-
#
|
51
|
-
# if chunks and isinstance(chunks[0], ChatCompletion):
|
52
|
-
# response = chunks[0]
|
53
|
-
# else:
|
54
|
-
# response = create_chat_completion(chunks)
|
55
|
-
# return response
|
56
36
|
image = None
|
57
37
|
prompt = request.last_user_content
|
58
38
|
if image_urls := request.last_urls.get("image_url"): # image_url
|
@@ -63,32 +43,55 @@ async def chat_for_image(
|
|
63
43
|
urls = await to_url(image_urls, content_type="image/png") # 数组
|
64
44
|
image = urls
|
65
45
|
|
66
|
-
|
46
|
+
image_request = ImageRequest(
|
67
47
|
model=request.model,
|
68
48
|
prompt=prompt,
|
69
49
|
image=image
|
70
50
|
)
|
71
|
-
if not
|
72
|
-
|
51
|
+
if not image_request.image:
|
52
|
+
image_request.image, image_request.prompt = image_request.image_and_prompt
|
73
53
|
|
74
|
-
if '--' in
|
75
|
-
prompt_dict = parse_command_string(
|
54
|
+
if '--' in image_request.prompt:
|
55
|
+
prompt_dict = parse_command_string(image_request.prompt)
|
76
56
|
# 缩写补充
|
77
57
|
prompt_dict['aspect_ratio'] = prompt_dict.get('aspect_ratio') or prompt_dict.get('ar')
|
78
58
|
|
79
59
|
data = {
|
80
|
-
**
|
60
|
+
**image_request.model_dump(exclude_none=True, exclude={"extra_fields", "aspect_ratio"}),
|
81
61
|
**prompt_dict
|
82
62
|
}
|
83
|
-
|
84
|
-
logger.debug(
|
63
|
+
image_request = ImageRequest(**data)
|
64
|
+
logger.debug(image_request)
|
85
65
|
|
66
|
+
# 非流式
|
67
|
+
if not request.stream or request.last_user_content.startswith( # 跳过nextchat
|
68
|
+
(
|
69
|
+
"hi",
|
70
|
+
"使用四到五个字直接返回这句话的简要主题",
|
71
|
+
"简要总结一下对话内容,用作后续的上下文提示 prompt,控制在 200 字以内"
|
72
|
+
)):
|
73
|
+
# chat_completion.choices[0].message.content = "请设置`stream=True`"
|
74
|
+
# return chat_completion
|
75
|
+
|
76
|
+
response = await generate(image_request)
|
77
|
+
|
78
|
+
if not isinstance(response, dict):
|
79
|
+
response = response.model_dump()
|
80
|
+
|
81
|
+
content = ""
|
82
|
+
for image in response['data']:
|
83
|
+
content += f"""\n\n"""
|
84
|
+
|
85
|
+
chat_completion.choices[0].message.content = content
|
86
|
+
return chat_completion
|
87
|
+
|
88
|
+
# 流式
|
86
89
|
if not generate: return
|
87
90
|
|
88
|
-
future_task = asyncio.create_task(generate(
|
91
|
+
future_task = asyncio.create_task(generate(image_request)) # 异步执行
|
89
92
|
|
90
93
|
async def gen():
|
91
|
-
text =
|
94
|
+
text = image_request.model_dump_json(exclude_none=True).replace("free", "")
|
92
95
|
for i in f"""> 🖌️正在绘画\n\n```json\n{text}\n```\n\n""":
|
93
96
|
await asyncio.sleep(0.05)
|
94
97
|
yield i
|
@@ -151,6 +154,7 @@ async def chat_for_video(
|
|
151
154
|
|
152
155
|
|
153
156
|
if __name__ == '__main__':
|
157
|
+
from meutils.apis.images.generations import generate
|
154
158
|
request = CompletionRequest(
|
155
159
|
model="deepseek-r1-Distill-Qwen-1.5B",
|
156
160
|
messages=[
|
@@ -159,3 +163,14 @@ if __name__ == '__main__':
|
|
159
163
|
stream=True,
|
160
164
|
)
|
161
165
|
arun(chat_for_image(None, request))
|
166
|
+
|
167
|
+
request = CompletionRequest(
|
168
|
+
model="gemini-2.5-flash-image-preview",
|
169
|
+
messages=[
|
170
|
+
{"role": "user", "content": "画条狗"}
|
171
|
+
],
|
172
|
+
# stream=True,
|
173
|
+
)
|
174
|
+
api_key = "sk-MAZ6SELJVtGNX6jgIcZBKuttsRibaDlAskFAnR7WD6PBSN6M-openai"
|
175
|
+
base_url = "https://new.yunai.link/v1"
|
176
|
+
arun(chat_for_image(generate, request, api_key, base_url))
|
meutils/schemas/oneapi/_types.py
CHANGED
@@ -52,7 +52,7 @@ class ChannelInfo(BaseModel):
|
|
52
52
|
access_token: str = ''
|
53
53
|
openai_organization: str = ''
|
54
54
|
test_model: str = ''
|
55
|
-
status: int = 1
|
55
|
+
status: int = 1 # 开启
|
56
56
|
weight: int = 0
|
57
57
|
created_time: int = Field(default_factory=lambda: int(time.time()))
|
58
58
|
test_time: int = 0
|
@@ -85,11 +85,15 @@ class ChannelInfo(BaseModel):
|
|
85
85
|
|
86
86
|
"""参数覆盖"""
|
87
87
|
param_override: Union[str, dict] = '' # json
|
88
|
+
header_override: Union[str, dict] = '' # json
|
88
89
|
is_tools: bool = False
|
89
90
|
|
90
91
|
# new
|
91
92
|
max_input_tokens: int = 0
|
92
|
-
|
93
|
+
|
94
|
+
mode:Optional[Literal["multi_to_single"]] = None
|
95
|
+
multi_key_mode: Literal['random', 'polling'] = "polling"
|
96
|
+
key_mode: Optional[Literal['append', 'replace']] = None
|
93
97
|
|
94
98
|
def __init__(self, /, **data: Any):
|
95
99
|
super().__init__(**data)
|
@@ -113,6 +117,9 @@ class ChannelInfo(BaseModel):
|
|
113
117
|
if isinstance(self.param_override, dict):
|
114
118
|
self.param_override = json.dumps(self.param_override)
|
115
119
|
|
120
|
+
if isinstance(self.header_override, dict):
|
121
|
+
self.header_override = json.dumps(self.header_override)
|
122
|
+
|
116
123
|
if isinstance(self.setting, dict):
|
117
124
|
self.setting = json.dumps(self.setting)
|
118
125
|
|
meutils/schemas/oneapi/common.py
CHANGED
@@ -666,6 +666,9 @@ MODEL_RATIO = {
|
|
666
666
|
"moonshotai/kimi-k2-instruct": 2,
|
667
667
|
"kimi-k2-0711-preview": 2,
|
668
668
|
"kimi-k2-turbo-preview": 2,
|
669
|
+
"kimi-k2-250711": 2,
|
670
|
+
"kimi-k2-250905": 2,
|
671
|
+
"kimi-k2-0905-preview": 2,
|
669
672
|
|
670
673
|
# 智谱 https://www.bigmodel.cn/pricing
|
671
674
|
'glm-4-9b-chat': 0.1,
|
@@ -710,6 +713,8 @@ MODEL_RATIO = {
|
|
710
713
|
"qwen-max-latest": 1.2 * 1,
|
711
714
|
"qwen2.5-max": 1.2 * 1,
|
712
715
|
"qwen-max-2025-01-25": 1.2 * 1,
|
716
|
+
"qwen3-max": 3,
|
717
|
+
"qwen3-max-preview": 3,
|
713
718
|
|
714
719
|
"qwen-vl-max-latest": 1.5,
|
715
720
|
"qwen-vl-plus-latest": 0.75,
|
@@ -1256,6 +1261,9 @@ COMPLETION_RATIO = {
|
|
1256
1261
|
"moonshotai/kimi-k2-instruct": 4,
|
1257
1262
|
"kimi-k2-0711-preview": 4,
|
1258
1263
|
"kimi-k2-turbo-preview": 4,
|
1264
|
+
"kimi-k2-250711": 4,
|
1265
|
+
"kimi-k2-250905": 4,
|
1266
|
+
"kimi-k2-0905-preview": 4,
|
1259
1267
|
|
1260
1268
|
"moonshot-v1-8k": 5,
|
1261
1269
|
"moonshot-v1-32k": 4,
|
@@ -1452,6 +1460,9 @@ COMPLETION_RATIO = {
|
|
1452
1460
|
|
1453
1461
|
"qwen-long": 4,
|
1454
1462
|
"qwen-max": 4,
|
1463
|
+
"qwen3-max": 4,
|
1464
|
+
"qwen3-max-preview": 4,
|
1465
|
+
|
1455
1466
|
"qwen-vl-max-latest": 3,
|
1456
1467
|
"qwen-vl-plus-latest": 3,
|
1457
1468
|
|
meutils/str_utils/__init__.py
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
|
11
11
|
|
12
12
|
from meutils.pipe import *
|
13
|
-
from meutils.str_utils.regular_expression import parse_url, parse_command_string
|
13
|
+
from meutils.str_utils.regular_expression import parse_url, parse_command_string, parse_base64
|
14
14
|
from meutils.request_utils.crawler import Crawler
|
15
15
|
from urllib.parse import urlencode, parse_qs, parse_qsl, quote_plus, unquote_plus, urljoin
|
16
16
|
|
@@ -114,6 +114,7 @@ def parse_url(text: str, for_image=False, fn: Optional[Callable] = None):
|
|
114
114
|
def parse_url_from_json():
|
115
115
|
pass
|
116
116
|
|
117
|
+
|
117
118
|
def parse_command_string(command_str: str) -> dict:
|
118
119
|
"""
|
119
120
|
解析一个类似 "prompt --key1 value1 --key2 value2" 格式的字符串。
|
@@ -188,6 +189,16 @@ def parse_command_string(command_str: str) -> dict:
|
|
188
189
|
return result
|
189
190
|
|
190
191
|
|
192
|
+
def parse_base64(text, pattern=r'!\[.*?\]\((.*?)\)'):
|
193
|
+
"""
|
194
|
+
:param text:
|
195
|
+
:param pattern:
|
196
|
+
pattern=r'!\[.*?\]\((data:image/.*?)\)'
|
197
|
+
:return:
|
198
|
+
"""
|
199
|
+
base64_strings = re.findall(pattern, text)
|
200
|
+
return base64_strings
|
201
|
+
|
191
202
|
|
192
203
|
if __name__ == '__main__':
|
193
204
|
# from urllib.parse import urlparse
|
@@ -258,7 +269,6 @@ https://i.miji.bid/2025/06/10/d018000aed9b872c7b248dccf14c4450.pngA
|
|
258
269
|
"""
|
259
270
|
print(parse_url(text, for_image=True))
|
260
271
|
|
261
|
-
|
262
272
|
# print(parse_url(text, for_image=False))
|
263
273
|
|
264
274
|
# text = """https://photog.art/api/oss/R2yh8N Convert this portrait into a straight-on,front-facing ID-style headshot."""
|
@@ -266,4 +276,9 @@ https://i.miji.bid/2025/06/10/d018000aed9b872c7b248dccf14c4450.pngA
|
|
266
276
|
#
|
267
277
|
# valid_urls = parse_url(text, for_image=True)
|
268
278
|
|
269
|
-
print(mimetypes.guess_type("xx.ico"))
|
279
|
+
print(mimetypes.guess_type("xx.ico"))
|
280
|
+
|
281
|
+
text = "这是一个示例文本,包含一个图片: 这张图片很棒。"
|
282
|
+
# text = "这是一个示例文本,。"
|
283
|
+
|
284
|
+
print(parse_base64(text * 2))
|