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.
@@ -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
- request = ImageRequest(
46
+ image_request = ImageRequest(
67
47
  model=request.model,
68
48
  prompt=prompt,
69
49
  image=image
70
50
  )
71
- if not request.image:
72
- request.image, request.prompt = request.image_and_prompt
51
+ if not image_request.image:
52
+ image_request.image, image_request.prompt = image_request.image_and_prompt
73
53
 
74
- if '--' in request.prompt:
75
- prompt_dict = parse_command_string(request.prompt)
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
- **request.model_dump(exclude_none=True, exclude={"extra_fields", "aspect_ratio"}),
60
+ **image_request.model_dump(exclude_none=True, exclude={"extra_fields", "aspect_ratio"}),
81
61
  **prompt_dict
82
62
  }
83
- request = ImageRequest(**data)
84
- logger.debug(request)
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"""![{image.get("revised_prompt")}]({image['url']})\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(request)) # 异步执行
91
+ future_task = asyncio.create_task(generate(image_request)) # 异步执行
89
92
 
90
93
  async def gen():
91
- text = request.model_dump_json(exclude_none=True).replace("free", "")
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))
@@ -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
- multi_key_mode: str = "random"
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
 
@@ -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
 
@@ -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 = "这是一个示例文本,包含一个图片:![image](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAIAAADwf7zUAAAgAElEQ) 这张图片很棒。"
282
+ # text = "这是一个示例文本,。"
283
+
284
+ print(parse_base64(text * 2))