MeUtils 2025.5.30.20.48.16__py3-none-any.whl → 2025.6.4.17.6.12__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.
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : sophnet
5
+ # @Time : 2025/6/4 16:16
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ from meutils.pipe import *
12
+ from meutils.llm.clients import AsyncOpenAI
13
+
14
+ from meutils.llm.check_utils import check_token_for_sophnet as check_token
15
+
16
+ from meutils.config_utils.lark_utils import get_next_token_for_polling
17
+ from meutils.schemas.openai_types import chat_completion, chat_completion_chunk, CompletionRequest, CompletionUsage, \
18
+ ChatCompletion
19
+
20
+ FEISHU_URL = "https://xchatllm.feishu.cn/sheets/Bmjtst2f6hfMqFttbhLcdfRJnNf?sheet=lxJ27j"
21
+
22
+ base_url = "https://www.sophnet.com/api/open-apis/v1"
23
+
24
+
25
+ async def create(request: CompletionRequest, token: Optional[str] = None):
26
+ """最终是非流"""
27
+ token = token or await get_next_token_for_polling(feishu_url=FEISHU_URL, from_redis=True, check_token=check_token)
28
+
29
+ client = AsyncOpenAI(base_url=base_url, api_key=token)
30
+
31
+ if not request.stream:
32
+ logger.debug("伪非流")
33
+
34
+ data = request.model_dump(exclude_none=True)
35
+ data['stream'] = True
36
+
37
+ chunks = await client.chat.completions.create(**data)
38
+
39
+ chunk = None
40
+ async for chunk in chunks:
41
+ if chunk.choices:
42
+ _ = chunk.choices[0].delta.content or ""
43
+ chat_completion.choices[0].message.content += _
44
+ # logger.debug(_)
45
+ if hasattr(chunk, "usage"):
46
+ chat_completion.usage = chunk.usage
47
+
48
+ logger.debug(chat_completion)
49
+ return chat_completion
50
+ else:
51
+ return client.chat.completions.create(**request.model_dump(exclude_none=True))
52
+
53
+
54
+ if __name__ == '__main__':
55
+ request = CompletionRequest(
56
+ model="DeepSeek-v3",
57
+ messages=[{"role": "user", "content": "hi"}],
58
+ stream=True,
59
+ )
60
+
61
+ arun(create(request))
@@ -200,8 +200,8 @@ if __name__ == '__main__':
200
200
  # model = 'deep_seek-search'
201
201
  model = 'deep_seek'
202
202
  # model = 'hunyuan_t1'
203
- model = 'hunyuan_t1-search'
204
- # model = 'deep_seek-search'
203
+ # model = 'hunyuan_t1-search'
204
+ model = 'deep_seek-search'
205
205
 
206
206
  arun(Completions().create(
207
207
  CompletionRequest(
@@ -82,9 +82,6 @@ class Completions(object):
82
82
  data.pop("frequency_penalty", None)
83
83
  data.pop("extra_body", None)
84
84
 
85
- if '2.5' in request.model and not request.reasoning_effort: # 默认关闭思考
86
- data['reasoning_effort'] = "none"
87
-
88
85
  if "thinking" in request.model:
89
86
  data['model'] = data['model'].removesuffix("-thinking") # 开启思考
90
87
  data['reasoning_effort'] = 'low'
@@ -9,10 +9,15 @@
9
9
  # @Description :
10
10
 
11
11
  from meutils.pipe import *
12
+ from meutils.io.files_utils import to_url, to_url_fal
12
13
  from meutils.schemas.openai_types import CompletionRequest
13
14
  from meutils.schemas.image_types import ImageRequest
14
15
  from meutils.llm.openai_utils import chat_completion, chat_completion_chunk, create_chat_completion_chunk
15
16
 
17
+ async def stream_to_nostream(
18
+ request: CompletionRequest,
19
+ ):
20
+ pass
16
21
 
17
22
  async def chat_for_image(
18
23
  generate: Callable,
@@ -24,14 +29,18 @@ async def chat_for_image(
24
29
  "使用四到五个字直接返回这句话的简要主题",
25
30
  "简要总结一下对话内容,用作后续的上下文提示 prompt,控制在 200 字以内"
26
31
  )):
27
- return
32
+ return chat_completion
33
+
34
+ prompt = request.last_user_content
35
+ if request.last_urls: # image_url
36
+ urls = await to_url_fal(request.last_urls["image_url"], content_type="image/png")
37
+ prompt = "\n".join(urls + [prompt])
28
38
 
29
39
  request = ImageRequest(
30
40
  model=request.model,
31
- prompt=request.last_user_content,
41
+ prompt=prompt,
32
42
  )
33
43
 
34
-
35
44
  future_task = asyncio.create_task(generate(request)) # 异步执行
36
45
 
37
46
  async def gen():
@@ -121,8 +121,11 @@ async def appu(
121
121
  model='ppu',
122
122
  api_key: Optional[str] = None,
123
123
  base_url: Optional[str] = None,
124
+
125
+ dynamic: bool = False, # 动态路由模型
126
+
124
127
  ):
125
- if model not in MODEL_PRICE:
128
+ if not dynamic and model not in MODEL_PRICE:
126
129
  _ = f"模型未找到「{model}」,默认ppu-1"
127
130
 
128
131
  logger.warning(_)
@@ -142,6 +145,9 @@ async def ppu_flow(
142
145
  post: str = "ppu-1", # 后计费
143
146
 
144
147
  pre: str = "ppu-0001", # 前置判断,废弃
148
+
149
+ dynamic: bool = False,
150
+
145
151
  **kwargs
146
152
  ):
147
153
  """
@@ -164,7 +170,7 @@ async def ppu_flow(
164
170
 
165
171
  # 计费逻辑
166
172
  n = int(np.round(n)) or 1 # np.ceil(n)
167
- await asyncio.gather(*[appu(post, api_key=api_key, base_url=base_url) for _ in range(n)])
173
+ await asyncio.gather(*[appu(post, api_key=api_key, base_url=base_url, dynamic=dynamic) for _ in range(n)])
168
174
 
169
175
  if money is None: # 先扣费
170
176
  yield
@@ -239,6 +245,19 @@ async def create_chat_completion_chunk(
239
245
  yield "[DONE]" # 兼容标准格式
240
246
 
241
247
 
248
+ def get_payment_times(request: Union[BaseModel, dict], duration: float = 5):
249
+ if isinstance(request, BaseModel):
250
+ request = request.model_dump()
251
+
252
+ # 数量
253
+ N = request.get("n") or request.get("num_images") or 1
254
+
255
+ # 时长
256
+ N += request.get("duration", 0) // duration
257
+
258
+ return N
259
+
260
+
242
261
  if __name__ == '__main__':
243
262
  # print(ppu())
244
263
  # print(appu())
meutils/llm/utils.py CHANGED
@@ -70,7 +70,7 @@ async def ppu_flow(
70
70
  yield
71
71
 
72
72
 
73
- def oneturn2multiturn(messages, template: Optional[str] = None):
73
+ def oneturn2multiturn(messages, template: Optional[str] = None, ignore_system: bool = True):
74
74
  """todo: https://github.com/hiyouga/LLaMA-Factory/blob/e898fabbe3efcd8b44d0e119e7afaed4542a9f39/src/llmtuner/data/template.py#L423-L427
75
75
 
76
76
  _register_template(
@@ -99,36 +99,67 @@ def oneturn2multiturn(messages, template: Optional[str] = None):
99
99
  # context += f"<|im_start|>{role}\n{content}<|im_end|>\n"
100
100
  # context += "<|im_start|>assistant\n"
101
101
  if len(messages) == 1:
102
- return messages[0].get("content")
102
+ content = messages[0].get("content")
103
+ if isinstance(content, list):
104
+ content = content[-1].get('text', '')
105
+ return content
103
106
 
104
107
  context = "\n"
105
108
  for message in messages:
106
109
  role = message.get("role")
107
110
  content = message.get("content")
111
+
108
112
  if isinstance(content, list): # content: {'type': 'text', 'text': ''}
109
113
  content = content[-1].get('text', '')
110
114
 
115
+ if role == "system" and ignore_system:
116
+ continue
117
+
111
118
  context += f"{role}:\n{content}\n\n"
112
- context += "assistant:\n"
113
- return context
114
119
 
120
+ return context
115
121
 
116
122
 
117
123
  if __name__ == '__main__':
118
- async def main():
119
- with timer():
120
- try:
121
- async with ppu_flow(
122
- api_key="sk-OYK4YxtTlWauT2TdGR5FTAJpkRmSnDwPly4cve0cAvMcrBkZ",
123
- model="api-oss",
124
- n=1):
125
- logger.debug("消费了哦")
126
-
127
- except Exception as e:
128
- pass
129
- logger.error(e)
130
- # logger.debug(e.response.status_code)
131
- # logger.debug(e.response.text)
132
-
133
-
134
- arun(main())
124
+ messages = [
125
+ {
126
+ "role": "system",
127
+ "content": [
128
+ {
129
+ "type": "text",
130
+ "text": "你是数学家"
131
+ }
132
+ ]
133
+ },
134
+ {
135
+ "role": "user",
136
+ "content": [
137
+ {
138
+ "type": "text",
139
+ "text": "1+1"
140
+ }
141
+ ]
142
+ },
143
+ {
144
+ "role": "assistant",
145
+ "content": [
146
+ {
147
+ "type": "text",
148
+ "text": "2"
149
+ }
150
+ ]
151
+ },
152
+
153
+ {
154
+ "role": "user",
155
+ "content": [
156
+ {
157
+ "type": "text",
158
+ "text": "1+2"
159
+ }
160
+ ]
161
+ },
162
+
163
+ ]
164
+
165
+ print(oneturn2multiturn(messages,ignore_system=False))
meutils/notice/feishu.py CHANGED
@@ -31,8 +31,8 @@ def send_message(
31
31
  url: str = DEFAULT,
32
32
  n: int = 1,
33
33
  ):
34
- logger.debug(f"数据类型:{type(content)}")
35
- logger.debug(content)
34
+ # logger.debug(f"数据类型:{type(content)}")
35
+ # logger.debug(content)
36
36
 
37
37
  if any((content, title)):
38
38
 
@@ -93,7 +93,7 @@ class ImageRequest(BaseModel): # openai
93
93
 
94
94
  aspect_ratio: Optional[str] = None
95
95
 
96
- user: Optional[str] = None
96
+ user: Optional[str] = None # to_url_fal
97
97
 
98
98
  def __init__(self, /, **data: Any):
99
99
  super().__init__(**data)
@@ -549,3 +549,6 @@ if __name__ == '__main__':
549
549
 
550
550
  request = ImageRequest(prompt=prompt)
551
551
  print(request.image_and_prompt)
552
+
553
+ data = {"image[]": "xxx"}
554
+ r = ImageRequest(**data)
@@ -149,9 +149,9 @@ MODEL_PRICE = {
149
149
  "ideogram-ai/ideogram-v2": 0.2,
150
150
  "ideogram-ai/ideogram-v2-turbo": 0.1,
151
151
 
152
- "imagen4": 0.05 * 2,
153
- "flux-kontext-pro": 0.04 * 2,
154
- "flux-kontext-max": 0.08 * 2,
152
+ "imagen4": 0.05 * 3,
153
+ "flux-kontext-pro": 0.04 * 3,
154
+ "flux-kontext-max": 0.08 * 3,
155
155
 
156
156
  "api-asr": 0.01,
157
157
  "api-stt": 0.01,
@@ -626,6 +626,7 @@ MODEL_RATIO = {
626
626
  "deepseek-r1-0528": 2,
627
627
  "deepseek-r1-250528": 2,
628
628
  "deepseek-r1-250528-qwen3-8b": 0.3,
629
+ "deepseek-r1-250528-think": 2,
629
630
 
630
631
  "deepseek-search": 1,
631
632
  'deepseek-r1-search': 2,
@@ -657,10 +658,14 @@ MODEL_RATIO = {
657
658
  "hunyuan-t1": 1,
658
659
  "hunyuan-t1-search": 1,
659
660
 
661
+ "hunyuan-r1-search": 2,
662
+
660
663
  "deepseek-r1-metasearch": 2,
661
664
  "meta-deepresearch": 2,
662
665
 
663
666
  # 豆包
667
+ "doubao-1-5-ui-tars-250428": 1.75,
668
+ "ui-tars-72b": 1.75,
664
669
  "doubao-1-5-pro-32k": 0.4,
665
670
  "doubao-1-5-pro-32k-250115": 0.4,
666
671
  "doubao-1-5-pro-256k": 2.5,
@@ -678,9 +683,9 @@ MODEL_RATIO = {
678
683
  "doubao-pro-32k": 0.4,
679
684
  "doubao-pro-32k-character": 0.4,
680
685
  "doubao-pro-128k": 2.5,
681
- "doubao-pro-256k": 5,
682
- "doubao-1.5-pro-32k": 0.8 / 2,
683
- "doubao-1.5-pro-256k": 5 / 2,
686
+ "doubao-pro-256k": 2.5,
687
+ "doubao-1.5-pro-32k": 0.4,
688
+ "doubao-1.5-pro-256k": 2.5,
684
689
 
685
690
  "doubao-1.5-vision-pro-32k": 1.5,
686
691
  "doubao-1.5-vision-pro-250328": 1.5,
@@ -900,6 +905,9 @@ MODEL_RATIO = {
900
905
  "o4-mini": 0.55,
901
906
  "gpt-image-1": 2.5,
902
907
 
908
+ "o3": 5,
909
+ "o3-2025-04-16": 5,
910
+
903
911
  # 硅基
904
912
  "llama-3.1-8b-instruct": 0.01,
905
913
  "meta-llama/Meta-Llama-3.1-8B-Instruct": 0.01,
@@ -1009,6 +1017,9 @@ COMPLETION_RATIO = {
1009
1017
  "o3-mini": 4,
1010
1018
  "o4-mini": 4,
1011
1019
 
1020
+ "o3": 4,
1021
+ "o3-2025-04-16": 4,
1022
+
1012
1023
  "gpt-4o-realtime-preview": 4,
1013
1024
  "gpt-4o-realtime-preview-2024-10-01": 4,
1014
1025
  "gpt-4o-2024-11-20": 4,
@@ -1177,20 +1188,22 @@ COMPLETION_RATIO = {
1177
1188
  "deepseek-ai/deepseek-vl2": 4,
1178
1189
 
1179
1190
  # 豆包
1191
+ "doubao-1-5-ui-tars-250428": 3.43,
1192
+ "ui-tars-72b": 4,
1193
+
1180
1194
  "doubao-lite-128k": 3,
1181
- "doubao-lite-32k": 3,
1195
+ "doubao-lite-32k": 2,
1182
1196
  "doubao-lite-32k-character": 3,
1183
1197
  "doubao-lite-4k": 3,
1184
1198
  "doubao-1.5-lite-32k": 2,
1185
1199
 
1186
1200
  "doubao-pro-4k": 3,
1187
- "doubao-pro-32k": 3,
1188
- "doubao-pro-32k-241215": 3,
1201
+ "doubao-pro-32k": 2.5,
1189
1202
  "doubao-pro-32k-character": 3,
1190
1203
  "doubao-pro-128k": 3,
1191
- "doubao-pro-256k": 3,
1192
- "doubao-1.5-pro-32k": 3,
1193
- "doubao-1.5-pro-256k": 3,
1204
+ "doubao-pro-256k": 1.8,
1205
+ "doubao-1.5-pro-32k": 2.5,
1206
+ "doubao-1.5-pro-256k": 1.8,
1194
1207
 
1195
1208
  "doubao-1.5-vision-pro-32k": 3,
1196
1209
  "doubao-1.5-vision-pro-250328": 3,
@@ -1202,7 +1215,7 @@ COMPLETION_RATIO = {
1202
1215
  "doubao-vision-pro-32k": 3,
1203
1216
 
1204
1217
  "doubao-1-5-pro-32k": 1.25,
1205
- "doubao-1-5-pro-32k-250115": 1.25,
1218
+ "doubao-1-5-pro-32k-250115": 2.5,
1206
1219
  "doubao-1-5-pro-256k": 1.8,
1207
1220
  "doubao-1-5-pro-256k-250115": 1.8,
1208
1221
 
@@ -1233,6 +1246,7 @@ COMPLETION_RATIO = {
1233
1246
 
1234
1247
  "hunyuan-t1": 4,
1235
1248
  "hunyuan-t1-search": 4,
1249
+ "hunyuan-r1-search": 4,
1236
1250
 
1237
1251
  "deepseek-r1-metasearch": 4,
1238
1252
  "meta-deepresearch": 4,
@@ -1249,6 +1263,7 @@ COMPLETION_RATIO = {
1249
1263
  "deepseek-r1-250120": 4,
1250
1264
  "deepseek-r1-0528": 4,
1251
1265
  "deepseek-r1-250528": 4,
1266
+ "deepseek-r1-250528-think": 4,
1252
1267
 
1253
1268
  "deepseek-r1-250528-qwen3-8b": 4,
1254
1269
 
@@ -620,10 +620,10 @@ if __name__ == '__main__':
620
620
  # print(chat_completion_chunk)
621
621
  # print(chat_completion)
622
622
 
623
- chat_completion_chunk.usage = dict(
624
- completion_tokens=10,
625
- prompt_tokens=10,
626
- total_tokens=20,
627
- )
628
-
629
- print(chat_completion_chunk)
623
+ # chat_completion_chunk.usage = dict(
624
+ # completion_tokens=10,
625
+ # prompt_tokens=10,
626
+ # total_tokens=20,
627
+ # )
628
+ #
629
+ # print(chat_completion_chunk)
@@ -47,6 +47,9 @@ async def get_bearer_token(
47
47
  elif ',' in token: # 内存里随机轮询
48
48
  token = np.random.choice(token.split(','))
49
49
 
50
+ elif token in {"none", "null"}:
51
+ token = None
52
+
50
53
  return token
51
54
 
52
55
 
@@ -26,7 +26,6 @@ def has_chinese(text):
26
26
  return bool(pattern.search(text))
27
27
 
28
28
 
29
-
30
29
  @lru_cache()
31
30
  def remove_date_suffix(filename):
32
31
  """
@@ -147,6 +146,7 @@ if __name__ == '__main__':
147
146
  https://oss.ffire.cc/files/%E6%8B%9B%E6%A0%87%E6%96%87%E4%BB%B6%E5%A4%87%E6%A1%88%E8%A1%A8%EF%BC%88%E7%AC%AC%E4%BA%8C%E6%AC%A1%EF%BC%89.pdf 这个文件讲了什么?
148
147
 
149
148
  """
149
+
150
150
  # https://oss.ffire.cc/files/%E6%8B%9B%E6%A0%87%E6%96%87%E4%BB%B6%E5%A4%87%E6%A1%88%E8%A1%A8%EF%BC%88%E7%AC%AC%E4%BA%8C%E6%AC%A1%EF%BC%89.pdf 正则匹配会卡死
151
151
  # from urllib3.util import parse_url
152
152
  # text = "@firebot /换衣 https://oss.ffire.cc/files/try-on.png"
@@ -163,10 +163,14 @@ if __name__ == '__main__':
163
163
 
164
164
  print(parse_url(text))
165
165
 
166
- print(parse_url("[](https://oss.ffire.cc/cdn/2025-03-20/YbHhMbrXV82XGn4msunAJw)"))
166
+ # print(parse_url("[](https://oss.ffire.cc/cdn/2025-03-20/YbHhMbrXV82XGn4msunAJw)"))
167
167
 
168
168
  # print('https://mj101-1317487292.cos.ap-shanghai.myqcloud.com/ai/test.pdf\\n\\n'.strip(r"\n"))
169
169
 
170
170
  # print(parse_url("http://154.3.0.117:39666/docs#/default/get_content_preview_spider_playwright_get"))
171
171
 
172
172
  # print(parse_url(text, True))
173
+ text = """
174
+ https://p3-bot-workflow-sign.byteimg.com/tos-cn-i-mdko3gqilj/1fe07cca46224208bfbed8c0f3c50ed8.png~tplv-mdko3gqilj-image.image?rk3s=81d4c505&x-expires=1780112531&x-signature=e7q1NOMjqCHvMz%2FC3dVAEVisAh4%3D&x-wf-file_name=9748f6214970f744fe7fd7a3699cfa2.png \nA young woman holding a lipstick tube with a black body and gold decorative rings, featuring a nude or light brown lipstick bullet. The lipstick product faces the camera, positioned slightly below her face. In the background, a close-up of lips coated with the same nude or light brown shade, creating a natural and soft effect.
175
+ """
176
+ print(parse_url(text, for_image=True))