MeUtils 2025.3.19.19.13.35__py3-none-any.whl → 2025.3.21.10.18.9__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.
@@ -6,12 +6,16 @@
6
6
  # @Author : betterme
7
7
  # @WeChat : meutils
8
8
  # @Software : PyCharm
9
- # @Description :
9
+ # @Description :
10
+ import asyncio
10
11
 
12
+ import shortuuid
11
13
 
12
14
  from meutils.pipe import *
13
15
  from meutils.llm.openai_utils import to_openai_params
14
16
  from meutils.llm.clients import AsyncOpenAI
17
+ from meutils.str_utils.regular_expression import parse_url
18
+ from meutils.io.files_utils import to_url, markdown_base64_to_url
15
19
 
16
20
  from meutils.schemas.openai_types import chat_completion, chat_completion_chunk, CompletionRequest, CompletionUsage
17
21
 
@@ -31,12 +35,18 @@ class Completions(object):
31
35
  base_url: Optional[str] = None,
32
36
  api_key: Optional[str] = None
33
37
  ):
38
+
39
+ base_url = "https://api.aiguoguo199.com/v1"
40
+
34
41
  self.client = AsyncOpenAI(
35
42
  base_url=base_url,
36
43
  api_key=api_key,
37
44
  )
38
45
 
39
46
  async def create(self, request: CompletionRequest):
47
+ if request.model == "gemini-2.0-flash-exp-image-generation":
48
+ return await self.images_create(request)
49
+
40
50
  urls = sum(request.last_urls.values(), [])
41
51
  for url in urls:
42
52
  request.messages[-1]["content"].append({"type": "image_url", "image_url": {"url": url}})
@@ -44,20 +54,74 @@ class Completions(object):
44
54
  data = to_openai_params(request)
45
55
  return await self.client.chat.completions.create(**data)
46
56
 
57
+ async def images_create(self, request: CompletionRequest):
58
+
59
+ if request.last_assistant_content and (urls := parse_url(request.last_assistant_content)):
60
+ for message in request.messages[::-1]:
61
+ if message.get("role") == "assistant":
62
+ message["content"] = [
63
+ {"type": "image_url", "image_url": {"url": url.removesuffix(")")}} for url in urls
64
+ ]
65
+
66
+ if urls := parse_url(request.last_user_content): # 修正提问格式, 兼容 url
67
+ for message in request.messages[::-1]:
68
+ if message.get("role") == "user":
69
+ message["content"] = [
70
+ {"type": "image_url", "image_url": {"url": url.removesuffix(")")}} for url in urls
71
+ ]
72
+ message["content"] += [{"type": "text", "text": request.last_user_content}]
73
+
74
+ # 调用模型
75
+ logger.debug(request.model_dump_json(indent=4))
76
+
77
+ data = to_openai_params(request)
78
+ response = await self.client.chat.completions.create(**data)
79
+
80
+ if request.stream:
81
+ return self.stream_create(response)
82
+
83
+ else:
84
+ content = response.choices[0].message.content
85
+ response.choices[0].message.content = await markdown_base64_to_url(content) # base64 转 url
86
+
87
+ if hasattr(response, "system_prompt"):
88
+ del response.system_prompt
89
+
90
+ return response
91
+
92
+ async def stream_create(self, chunks):
93
+ async for chunk in chunks:
94
+ if hasattr(chunk, "system_prompt"):
95
+ del chunk.system_prompt
96
+
97
+ if (content := chunk.choices[0].delta.content) and content.startswith("!["):
98
+ chunk.choices[0].delta.content = await markdown_base64_to_url(content)
99
+
100
+ yield chunk
101
+ else:
102
+ yield chunk
103
+ logger.debug(str(chunk))
104
+
47
105
 
48
106
  if __name__ == '__main__':
49
107
  url = "https://oss.ffire.cc/files/lipsync.mp3"
50
108
  url = "https://lmdbk.com/5.mp4"
51
109
  content = [
52
- {"type": "text", "text": "总结下"},
110
+
111
+ {"type": "text", "text": "https://oss.ffire.cc/files/nsfw.jpg 移除右下角的水印"},
112
+
113
+ # {"type": "text", "text": "总结下"},
53
114
  # {"type": "image_url", "image_url": {"url": url}},
54
115
 
55
- {"type": "video_url", "video_url": {"url": url}}
116
+ # {"type": "video_url", "video_url": {"url": url}}
56
117
 
57
118
  ]
119
+
120
+ #
58
121
  request = CompletionRequest(
59
122
  # model="qwen-turbo-2024-11-01",
60
- model="gemini-all",
123
+ # model="gemini-all",
124
+ model="gemini-2.0-flash-exp-image-generation",
61
125
  # model="qwen-plus-latest",
62
126
 
63
127
  messages=[
@@ -68,6 +132,9 @@ if __name__ == '__main__':
68
132
  },
69
133
 
70
134
  ],
71
- stream=False,
135
+ stream=True,
72
136
  )
73
- arun(Completions().create(request))
137
+
138
+ api_key = "sk-Q2XxJBh3KM7bTptL6e96E8596fC74426BaA87528867aA77b"
139
+
140
+ arun(Completions(api_key=api_key).create(request))
@@ -76,7 +76,7 @@ class Completions(object):
76
76
  }
77
77
  ]
78
78
  data = to_openai_params(request)
79
- return self.client.chat.completions.create(**data)
79
+ return await self.client.chat.completions.create(**data)
80
80
 
81
81
  elif guess_mime_type(file_url).startswith(("video", "audio")): # 音频 视频
82
82
  request.model = "gemini" # 果果
@@ -98,7 +98,7 @@ class Completions(object):
98
98
  }
99
99
  ]
100
100
  data = to_openai_params(request)
101
- return self.client.chat.completions.create(**data)
101
+ return await self.client.chat.completions.create(**data)
102
102
 
103
103
  else:
104
104
 
@@ -111,18 +111,18 @@ class Completions(object):
111
111
  }
112
112
  ]
113
113
  data = to_openai_params(request)
114
- return self.client.chat.completions.create(**data)
114
+ return await self.client.chat.completions.create(**data)
115
115
 
116
116
  if image_urls := request.last_urls.get("image_url"): # 识图
117
117
  request.model = "glm-4v-flash"
118
118
  data = to_openai_params(request)
119
- return self.client.chat.completions.create(**data)
119
+ return await self.client.chat.completions.create(**data)
120
120
 
121
121
  elif file_urls := request.last_urls.get("file_url"):
122
- return self.chat_files(request)
122
+ return await self.chat_files(request)
123
123
 
124
124
  data = to_openai_params(request)
125
- return self.client.chat.completions.create(**data)
125
+ return await self.client.chat.completions.create(**data)
126
126
 
127
127
  async def chat_files(self, request: CompletionRequest): # 多轮
128
128
  for i, message in enumerate(request.messages[::-1], 1):
@@ -142,7 +142,7 @@ class Completions(object):
142
142
  break # 截断:从最新的文件开始
143
143
 
144
144
  data = to_openai_params(request)
145
- return self.client.chat.completions.create(**data)
145
+ return await self.client.chat.completions.create(**data)
146
146
 
147
147
  async def create_images(self, request: CompletionRequest):
148
148
 
@@ -153,7 +153,13 @@ class Completions(object):
153
153
  )
154
154
  image_url = response.data[0].url
155
155
  tool_desc = """> images.generate\n\n"""
156
- return tool_desc + f"![{request.last_user_content}]({image_url})"
156
+ tool_desc += f"![{request.last_user_content}]({image_url})"
157
+ if not request.stream:
158
+ chat_completion.choices[0].message.content = tool_desc
159
+ return chat_completion
160
+ return tool_desc
161
+
162
+ # chat_completion_chunk
157
163
 
158
164
  # async def create_videos(self, request: CompletionRequest):
159
165
  #
@@ -169,9 +175,9 @@ if __name__ == '__main__':
169
175
  c = Completions()
170
176
 
171
177
  request = CompletionRequest(
172
- model="qwen-turbo-2024-11-01",
178
+ # model="qwen-turbo-2024-11-01",
173
179
  # model="claude-3-5-sonnet-20241022",
174
- # model="gpt-4o-mini",
180
+ model="gpt-4o-mini",
175
181
 
176
182
  messages=[{
177
183
  'role': 'user',
@@ -181,10 +187,12 @@ if __name__ == '__main__':
181
187
  "text": "总结下"
182
188
  },
183
189
 
184
- # {
185
- # "type": "image_url",
186
- # "image_url": "https://oss.ffire.cc/files/招标文件备案表(第二次).pdf"
187
- # }
190
+ {
191
+ "type": "file_url",
192
+ "file_url": {
193
+ "url": "https://oss.ffire.cc/files/招标文件备案表(第二次).pdf"
194
+ }
195
+ }
188
196
  ]
189
197
  }])
190
198
 
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : chat_videos
5
+ # @Time : 2025/3/20 10:19
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+
12
+ from meutils.pipe import *
13
+ from meutils.llm.clients import AsyncOpenAI
14
+ from meutils.apis.chatglm import glm_video_api # VideoRequest, create_task, get_task
15
+ from meutils.str_utils.regular_expression import parse_url
16
+
17
+ from meutils.schemas.openai_types import chat_completion, chat_completion_chunk, CompletionRequest, CompletionUsage
18
+
19
+
20
+ class Completions(object):
21
+
22
+ def __init__(self,
23
+ base_url: Optional[str] = None,
24
+ api_key: Optional[str] = None
25
+ ):
26
+ self.client = AsyncOpenAI(
27
+ base_url=base_url,
28
+ api_key=api_key,
29
+ )
30
+
31
+ async def create(self, request: CompletionRequest):
32
+
33
+ image_url = None
34
+ prompt = request.last_user_content
35
+ if urls := parse_url(prompt):
36
+ image_url = urls[0]
37
+ prompt = prompt.replace(image_url, "")
38
+
39
+ # 创建任务
40
+ video_request = glm_video_api.VideoRequest(image_url=image_url, prompt=prompt)
41
+ response = await glm_video_api.create_task(video_request)
42
+ taskid = response.id
43
+ system_fingerprint = response.system_fingerprint
44
+
45
+ # 获取任务
46
+ for i in f"""> VideoTask(id={taskid.split('-')[-1]}, image_url={image_url}, prompt={prompt})\n""":
47
+ await asyncio.sleep(0.03)
48
+ yield i
49
+
50
+ yield f"[🤫 任务进度]("
51
+ for i in range(60):
52
+ await asyncio.sleep(3)
53
+ response = await glm_video_api.get_task(taskid, system_fingerprint)
54
+
55
+ logger.debug(response)
56
+ if response.task_status == "SUCCESS" or response.video_result:
57
+ yield ")🎉🎉🎉\n\n"
58
+ for video in response.video_result or []:
59
+ yield f"[^1]: [封面]({video.cover_image_url})\n\n"
60
+ yield f"[^2]: [视频]({video.url})\n\n"
61
+
62
+ yield f"[视频]({video.url})[^1][^2]\n\n"
63
+ yield f"![视频]({video.url})[^1][^2]\n\n"
64
+
65
+ break
66
+ else:
67
+ yield "🔥"
68
+
69
+
70
+ if __name__ == '__main__':
71
+ url = "https://oss.ffire.cc/files/lipsync.mp3"
72
+ url = "https://lmdbk.com/5.mp4"
73
+ content = [
74
+ {"type": "text", "text": "总结下"},
75
+ # {"type": "image_url", "image_url": {"url": url}},
76
+
77
+ {"type": "video_url", "video_url": {"url": url}}
78
+
79
+ ]
80
+ request = CompletionRequest(
81
+ # model="qwen-turbo-2024-11-01",
82
+ model="gemini-all",
83
+ # model="qwen-plus-latest",
84
+
85
+ messages=[
86
+ {
87
+ 'role': 'user',
88
+
89
+ 'content': content
90
+ },
91
+
92
+ ],
93
+ stream=False,
94
+ )
95
+ arun(Completions().create(request))
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : deepx
5
+ # @Time : 2025/3/20 08:53
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+ """
11
+ deep + claude
12
+
13
+ """
14
+
15
+ from openai import AsyncOpenAI
16
+
17
+ from meutils.pipe import *
18
+ from meutils.decorators.retry import retrying
19
+ from meutils.io.files_utils import to_bytes
20
+ from meutils.io.openai_files import file_extract, guess_mime_type
21
+ from meutils.str_utils.json_utils import json_path
22
+ from meutils.apis.search import metaso
23
+ # from meutils.apis.chatglm import glm_video_api
24
+
25
+ from meutils.llm.clients import chatfire_client, zhipuai_client, AsyncOpenAI
26
+ from meutils.llm.openai_utils import to_openai_params
27
+
28
+ from meutils.schemas.openai_types import ChatCompletionRequest
29
+ from meutils.schemas.openai_types import chat_completion, chat_completion_chunk, CompletionRequest, ImageRequest
30
+
31
+
32
+ class Completions(object):
33
+
34
+ def __init__(self, api_key: Optional[str] = None):
35
+ self.api_key = api_key
36
+ self.client = AsyncOpenAI(api_key=api_key)
37
+
38
+ async def create(self, request: CompletionRequest):
39
+ """
40
+ :param request:
41
+ :return:
42
+ """
43
+ data = to_openai_params(request)
44
+ data['model'] = 'deepseek-reasoner'
45
+ data['max_tokens'] = 1 # 火山 支持max_tokens=1输出思维链
46
+ if request.stream:
47
+ reasoning_content = ""
48
+ completions = await chatfire_client.chat.completions.create(**data)
49
+ async for chunk in completions:
50
+ yield chunk
51
+ delta = chunk.choices[0].delta
52
+ if hasattr(delta, "reasoning_content"):
53
+ reasoning_content += delta.reasoning_content
54
+
55
+ request.messages = [
56
+ {
57
+ 'role': 'user',
58
+ 'content': f"""<think>\n\n{reasoning_content}\n\n</think>\n\n{request.last_user_content}"""
59
+ }
60
+ ]
61
+ data = to_openai_params(request)
62
+ async for chunk in await self.client.chat.completions.create(**data):
63
+ yield chunk
64
+ else:
65
+ reasoning_content = ""
66
+ completions = await chatfire_client.chat.completions.create(**data)
67
+ message = completions.choices[0].message
68
+ if hasattr(message, "reasoning_content"):
69
+ reasoning_content += message.reasoning_content
70
+
71
+ request.messages = [
72
+ {
73
+ 'role': 'user',
74
+ 'content': f"""<think>\n\n{reasoning_content}\n\n</think>\n\n\n{request.last_user_content}"""
75
+ }
76
+ ]
77
+ data = to_openai_params(request)
78
+ _completions = await self.client.chat.completions.create(**data)
79
+ completions.choices[0].message.content = _completions.choices[0].message.content
80
+ yield completions
81
+
82
+ async def screate(self, request: CompletionRequest):
83
+ pass
84
+
85
+
86
+ if __name__ == '__main__':
87
+ c = Completions()
88
+
89
+ request = CompletionRequest(
90
+ # model="qwen-turbo-2024-11-01",
91
+ # model="claude-3-5-sonnet-20241022",
92
+ model="deepseek-chat",
93
+ stream=True,
94
+
95
+ messages=[{
96
+ 'role': 'user',
97
+ 'content': "1+1"
98
+ }])
99
+
100
+ arun(c.create(request))
meutils/oss/__init__.py CHANGED
@@ -8,13 +8,7 @@
8
8
  # @Software : PyCharm
9
9
  # @Description :
10
10
 
11
- from meutils.pipe import *
12
11
 
13
12
 
14
- def upload(file: bytes, purpos="zhipu"):
15
- from meutils.oss.minio_oss import Minio
16
- from meutils.apis.chatglm.glm_video import upload_task
17
-
18
- file_task = upload_task(file)
19
13
 
20
14
 
@@ -425,7 +425,7 @@ MODEL_RATIO = {
425
425
  "qwen2.5-math-72b-instruct": 2,
426
426
  "qwen2.5-coder-32b-instruct": 0.5,
427
427
 
428
- "qwq-32b": 2,
428
+ "qwq-32b": 1,
429
429
  "qwq-max": 2,
430
430
  "qwq-max-search": 2,
431
431
  "qwen-max-search": 2,
@@ -858,8 +858,8 @@ COMPLETION_RATIO = {
858
858
 
859
859
  "gemini-2.0-flash-lite-preview-02-05": 4,
860
860
 
861
- "gemini-2.0-pro": 4,
862
- "gemini-2.0-pro-exp-02-05": 4,
861
+ "gemini-2.0-pro": 5,
862
+ "gemini-2.0-pro-exp-02-05": 5,
863
863
 
864
864
  "gemma2-9b-it": 4,
865
865
  "gemma2-27b-it": 4,
@@ -871,6 +871,8 @@ COMPLETION_RATIO = {
871
871
  "qwen-turbo-2024-11-01": 3,
872
872
  "qwen/qwq-32b-preview": 3,
873
873
  "Qwen/QwQ-32B-Preview": 3,
874
+ "qwq-32b": 3,
875
+
874
876
  "qwq-32b-preview": 3,
875
877
  "qvq-72b-preview": 3,
876
878
 
@@ -121,9 +121,6 @@ class CompletionRequest(BaseModel):
121
121
  def __init__(self, **kwargs):
122
122
  super().__init__(**kwargs)
123
123
 
124
- class Config:
125
- extra = "allow"
126
-
127
124
  @cached_property
128
125
  def last_message(self):
129
126
  return self.messages and self.messages[-1]
@@ -132,12 +129,23 @@ class CompletionRequest(BaseModel):
132
129
  def last_user_content(self) -> str:
133
130
  for i, message in enumerate(self.messages[::-1], 1):
134
131
  if message.get("role") == "user":
135
- user_contents = message.get("content")
136
- if isinstance(user_contents, list):
137
- for content in user_contents:
132
+ contents = message.get("content")
133
+ if isinstance(contents, list):
134
+ for content in contents:
138
135
  return content.get('text', "")
139
136
  else:
140
- return str(user_contents)
137
+ return str(contents)
138
+
139
+ @cached_property
140
+ def last_assistant_content(self) -> str:
141
+ for i, message in enumerate(self.messages[::-1], 1):
142
+ if message.get("role") == "assistant":
143
+ contents = message.get("content")
144
+ if isinstance(contents, list):
145
+ for content in contents:
146
+ return content.get('text', "")
147
+ else:
148
+ return str(contents)
141
149
 
142
150
  @cached_property
143
151
  def last_urls(self): # file_url 多轮对话需要 sum(request.last_urls.values(), [])
@@ -180,6 +188,24 @@ class CompletionRequest(BaseModel):
180
188
  #
181
189
  # return message
182
190
 
191
+ class Config:
192
+ extra = "allow"
193
+
194
+ json_schema_extra = {
195
+ "examples": [
196
+ {
197
+ "model": "deepseek-chat",
198
+ "messages": [
199
+ {
200
+ "role": "user",
201
+ "content": "hi"
202
+ }
203
+ ],
204
+ "stream": True
205
+ },
206
+ ]
207
+ }
208
+
183
209
 
184
210
  class ChatCompletionRequest(BaseModel):
185
211
  """
@@ -20,6 +20,8 @@ HTML_PARSER = re.compile(r'```html(.*?)```', re.DOTALL)
20
20
 
21
21
  # re.sub(r'=(.+)', r'=123','s=xxxxx')
22
22
 
23
+
24
+
23
25
  @lru_cache()
24
26
  def remove_date_suffix(filename):
25
27
  """
@@ -152,6 +154,8 @@ if __name__ == '__main__':
152
154
 
153
155
  print(parse_url(text))
154
156
 
157
+ print(parse_url("[](https://oss.ffire.cc/cdn/2025-03-20/YbHhMbrXV82XGn4msunAJw)"))
158
+
155
159
  # print('https://mj101-1317487292.cos.ap-shanghai.myqcloud.com/ai/test.pdf\\n\\n'.strip(r"\n"))
156
160
 
157
161
  # print(parse_url("http://154.3.0.117:39666/docs#/default/get_content_preview_spider_playwright_get"))