MeUtils 2025.4.20.23.17.29__py3-none-any.whl → 2025.4.23.16.0.20__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.
@@ -23,8 +23,9 @@ from meutils.schemas.openai_types import chat_completion, chat_completion_chunk,
23
23
  from meutils.config_utils.lark_utils import get_next_token_for_polling
24
24
  from google import genai
25
25
  from google.genai import types
26
- from google.genai.types import UploadFileConfig, HttpOptions, GenerateContentConfig, HarmCategory, HarmBlockThreshold, \
27
- Part
26
+ from google.genai.types import Part, HttpOptions, HarmCategory, HarmBlockThreshold
27
+ from google.genai.types import UploadFileConfig, ThinkingConfig, GenerateContentConfig
28
+
28
29
  from google.genai.types import UserContent, ModelContent, Content
29
30
  from google.genai.types import Tool, GoogleSearch
30
31
 
@@ -76,7 +77,8 @@ class Completions(object):
76
77
  model=request.model,
77
78
  config=GenerateContentConfig(
78
79
  tools=tools,
79
- system_instruction=request.system_instruction or "请根据用户的语言偏好自动调整回复语言"
80
+ system_instruction=request.system_instruction or "请根据用户的语言偏好自动调整回复语言",
81
+ # thinking_config=ThinkingConfig(include_thoughts=True, thinking_budget=24576)
80
82
  ),
81
83
  )
82
84
  # print(response.candidates[0].grounding_metadata.search_entry_point.rendered_content)
@@ -112,10 +114,27 @@ class Completions(object):
112
114
  url, user_content = request.last_user_content.split(maxsplit=1)
113
115
  file_object = await self.upload(url)
114
116
 
115
- logger.debug(file_object)
116
- if file_object.state.name != "PROCESSING":
117
- # _ = self.client.files.get(name=file_object.name)
117
+ yield f"> {file_object.model_dump_json(indent=4)}\n"
118
+ yield f"> [正在解析...]("
119
+
120
+ s = time.time()
121
+ for i in range(100):
122
+ await asyncio.sleep(3)
123
+ file_object = self.client.files.get(
124
+ name=file_object.name,
125
+ config={"http_options": {"timeout": 300 * 1000}}
126
+ )
127
+
118
128
  logger.debug(file_object)
129
+ if file_object.state.name == "ACTIVE":
130
+ yield f" 100% {int(time.time() - s)}s.)\n\n"
131
+ break
132
+ else:
133
+ yield f"{min(i * 5, 99)}% "
134
+
135
+ # while file_object.state.name == "ACTIVE":
136
+ # logger.debug(file_object)
137
+ # await asyncio.sleep(1)
119
138
 
120
139
  contents += [file_object, user_content]
121
140
  else:
@@ -127,7 +146,8 @@ class Completions(object):
127
146
  model=request.model,
128
147
  config=GenerateContentConfig(
129
148
  response_modalities=['Text'],
130
- system_instruction=request.system_instruction
149
+ system_instruction=request.system_instruction,
150
+ thinking_config=ThinkingConfig(thinking_budget=request.reasoning_effort and 1024 or 0)
131
151
  )
132
152
  )
133
153
  for i in range(5):
@@ -149,6 +169,9 @@ class Completions(object):
149
169
  await asyncio.sleep(1)
150
170
  continue
151
171
  else:
172
+ # {'error': {'code': 400,
173
+ # 'message': 'The File cwjpskscrjd79hjezu7dhb is not in an ACTIVE state and usage is not allowed.',
174
+ # 'status': 'FAILED_PRECONDITION'}}
152
175
  yield e
153
176
  raise e
154
177
 
@@ -317,7 +340,7 @@ class Completions(object):
317
340
  file_config = {
318
341
  "name": f"{shortuuid.random().lower()}",
319
342
  "mime_type": guess_mime_type(files),
320
- # "http_options": {"timeout": 1111111}
343
+ "http_options": {"timeout": 300 * 1000}
321
344
  }
322
345
 
323
346
  return await self.client.aio.files.upload(file=io.BytesIO(await to_bytes(files)), config=file_config)
@@ -331,7 +354,7 @@ class Completions(object):
331
354
  api_key=api_key,
332
355
  http_options=HttpOptions(
333
356
  base_url=self.base_url,
334
- timeout=120 * 1000000,
357
+ timeout=300 * 1000,
335
358
  )
336
359
  )
337
360
 
@@ -350,7 +373,8 @@ if __name__ == '__main__':
350
373
  # {"type": "text", "text": "https://oss.ffire.cc/files/nsfw.jpg 移除右下角的水印"},
351
374
  # {"type": "text", "text": "https://oss.ffire.cc/files/kling_watermark.png 总结下"},
352
375
  # {"type": "text", "text": "https://oss.ffire.cc/files/nsfw.jpg 总结下"},
353
- {"type": "text", "text": "https://lmdbk.com/5.mp4 总结下"},
376
+ # {"type": "text", "text": "https://lmdbk.com/5.mp4 总结下"},
377
+ {"type": "text", "text": "https://v3.fal.media/files/penguin/Rx-8V0MVgkVZM6PJ0RiPD_douyin.mp4 总结下"},
354
378
 
355
379
  # {"type": "text", "text": "总结下"},
356
380
  # {"type": "image_url", "image_url": {"url": url}},
@@ -68,8 +68,7 @@ if __name__ == '__main__':
68
68
  max_output_tokens=None,
69
69
  # response_modalities=['Text', 'Image'],
70
70
 
71
- thinking_config=ThinkingConfig(include_thoughts=True),
72
-
71
+ thinking_config=ThinkingConfig(include_thoughts=True, thinking_budget=24576),
73
72
  ),
74
73
 
75
74
  # history=[
@@ -124,7 +123,7 @@ if __name__ == '__main__':
124
123
  #
125
124
  async def main():
126
125
  message = [
127
- Part.from_text(text="画条狗 带个眼镜"),
126
+ Part.from_text(text="1+1"),
128
127
  # pp
129
128
  ]
130
129
 
@@ -170,3 +169,26 @@ if __name__ == '__main__':
170
169
  arun(main())
171
170
 
172
171
  # ValueError: Message must be a valid part type: typing.Union[google.genai.types.File, google.genai.types.Part, PIL.Image.Image, str] or typing.Union[google.genai.types.File, google.genai.types.Part, PIL.Image.Image, str, google.genai.types.PartDict], got <class 'list'>
172
+
173
+ """
174
+ curl "https://all.chatfire.cc/genai/v1beta/models/gemini-2.5-flash-preview-04-17:generateContent?key=AIzaSyCa8PYURpxFKz7yOtQB_O_wRfrX0gYh9L4" \
175
+ -H 'Content-Type: application/json' \
176
+ -X POST \
177
+ -d '{
178
+ "contents": [
179
+ {
180
+ "parts": [
181
+ {
182
+ "text": "9.8 9.11 哪个大"
183
+ }
184
+ ]
185
+ }
186
+ ],
187
+ "generationConfig": {
188
+ "thinkingConfig": {
189
+ "includeThoughts": true,
190
+ "thinkingBudget": 1024
191
+ }
192
+ }
193
+ }'
194
+ """
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : upload
5
+ # @Time : 2025/4/21 16:05
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ from meutils.pipe import *
12
+ import asyncio
13
+ import httpx
14
+ import os
15
+ import mimetypes
16
+ import json
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ mime_type = mimetypes.guess_type("x.html")[0] or "application/octet-stream"
21
+
22
+ print(mime_type)
23
+
24
+ num_bytes = len(Path("x.html").read_bytes())
25
+
26
+ headers = {
27
+ "X-Goog-Upload-Protocol": "resumable",
28
+ "X-Goog-Upload-Command": "start",
29
+ "X-Goog-Upload-Header-Content-Length": str(num_bytes),
30
+ "X-Goog-Upload-Header-Content-Type": mime_type,
31
+ "Content-Type": "application/json",
32
+
33
+
34
+
35
+ }
36
+ # payload = {'file': {'display_name': "TEXT"}}
37
+ payload = {}
38
+ base_url = "https://all.chatfire.cc/genai"
39
+
40
+ client = httpx.Client(base_url=base_url, headers=headers)
41
+
42
+ response = client.post("/upload/v1beta/files", params={"key": os.getenv("GOOGLE_API_KEY")}, json=payload)
43
+
44
+ print(dict(response.headers))
45
+ upload_url = response.headers.get("x-goog-upload-url")
46
+ print(upload_url)
47
+
48
+ headers = {"X-Goog-Upload-Offset": "0",
49
+ "X-Goog-Upload-Command": "upload, finalize", **headers}
50
+
51
+ response = httpx.post(url=upload_url, headers=headers, content=Path("x.html").read_bytes())
@@ -49,7 +49,7 @@ async def create_draft_content(request: ImageRequest, token: str):
49
49
 
50
50
  height = width = 1328
51
51
  if 'x' in request.size:
52
- height, width = map(int, request.size.split('x'))
52
+ width, height = map(int, request.size.split('x'))
53
53
 
54
54
  main_component_id = str(uuid.uuid4())
55
55
  if (urls := parse_url(request.prompt)) or image_uri: # 图生 # todo: image base64
@@ -31,22 +31,30 @@ async def get_one_proxy():
31
31
  if __name__ == '__main__':
32
32
  # arun(get_proxy_list())
33
33
 
34
- page_url = "http://icanhazip.com/" # 要访问的目标网页
34
+ page_url = "https://icanhazip.com/" # 要访问的目标网页
35
+ # page_url = "https://httpbin.org/ip"
35
36
 
36
37
 
37
38
  async def fetch(url):
38
- proxy = await get_one_proxy()
39
- # proxy = "http://154.9.253.9:38443"
40
-
41
- async with httpx.AsyncClient(proxy=proxy, timeout=20) as client:
39
+ # proxy = await get_one_proxy()
40
+ proxy = "http://154.9.253.9:38443"
41
+ # proxy="https://tinyproxy.chatfire.cn"
42
+ # proxy="https://pp.chatfire.cn"
43
+ proxy="http://110.42.51.201:38443"
44
+ proxy="http://110.42.51.223:38443"
45
+ proxy = "http://110.42.51.223:38443"
46
+
47
+ # proxy=None
48
+ proxy="https://npjdodcrxljt.ap-northeast-1.clawcloudrun.com"
49
+
50
+ async with httpx.AsyncClient(proxy=proxy, timeout=30) as client:
42
51
  resp = await client.get(url)
43
- print(f"status_code: {resp.status_code}, content: {resp.content}")
44
-
52
+ logger.debug((f"status_code: {resp.status_code}, content: {resp.text}"))
45
53
 
46
54
  def run():
47
55
  loop = asyncio.get_event_loop()
48
56
  # 异步发出5次请求
49
- tasks = [fetch(page_url) for _ in range(5)]
57
+ tasks = [fetch(page_url) for _ in range(3)]
50
58
  loop.run_until_complete(asyncio.wait(tasks))
51
59
 
52
60
 
@@ -90,7 +90,10 @@ class Completions(object):
90
90
  if isinstance(request, CompletionRequest):
91
91
  if references:
92
92
  urls = [f"[^{i}]: [{ref['title']}]({ref['link']})\n" for i, ref in enumerate(references, 1)]
93
- yield from urls
93
+
94
+ for url in urls:
95
+ yield url
96
+
94
97
  references = []
95
98
 
96
99
  delta = chat_completion_chunk.choices[0].delta.model_construct(**delta.model_dump())
@@ -119,5 +122,5 @@ if __name__ == '__main__':
119
122
 
120
123
  stream=True
121
124
  )
122
- # arun(Completions().create(request))
125
+ print(Completions().create(request))
123
126
  # arun(Completions().query(request.last_user_content))
@@ -89,15 +89,16 @@ if __name__ == '__main__':
89
89
  3D魔童哪吒 c4d 搬砖 很开心, 很快乐, 精神抖擞, 背景是数不清的敖丙虚化 视觉冲击力强 大师构图 色彩鲜艳丰富 吸引人 背景用黄金色艺术字写着“搬砖挣钱” 冷暖色对比
90
90
  """
91
91
 
92
- prompt = """
93
- https://oss.ffire.cc/files/kling_watermark.png
94
- 让这个女人带上眼镜 衣服换个颜色
95
- """
92
+ # prompt = """
93
+ # https://oss.ffire.cc/files/kling_watermark.png
94
+ # 让这个女人带上眼镜 衣服换个颜色
95
+ # """
96
96
 
97
97
  request = ImageRequest(
98
98
  model="high_aes_general_v30l_zt2i",
99
99
  prompt=prompt,
100
100
  response_format="url",
101
+ size="512x1328",
101
102
  )
102
103
 
103
104
  arun(generate(request, token=token))
meutils/data/VERSION CHANGED
@@ -1 +1 @@
1
- 2025.04.20.23.17.29
1
+ 2025.04.23.16.00.20
meutils/db/redis_db.py CHANGED
@@ -94,5 +94,7 @@ if __name__ == '__main__':
94
94
 
95
95
  # arun(main())
96
96
 
97
- r = redis_client.sadd('set1', 'a', 'b', 'c')
98
- r = redis_client.sadd('set1', 'd')
97
+ # r = redis_client.sadd('set1', 'a', 'b', 'c')
98
+ # r = redis_client.sadd('set1', 'd')
99
+ k="meutils.config_utils.lark_utils.commonaget_spreadsheet_values()[('feishu_url', 'https://xchatllm.feishu.cn/sheets/GYCHsvI4qhnDPNtI4VPcdw2knEd?sheet=Gvm9dt'), ('to_dataframe', True)] "
100
+ redis_client.delete(k)
meutils/io/files_utils.py CHANGED
@@ -69,7 +69,7 @@ async def to_bytes(
69
69
  elif isinstance(file, str):
70
70
  if file.startswith('http'):
71
71
  logger.debug(f"FileType: HTTP")
72
- async with AsyncClient(headers=headers or {}, timeout=120) as cilent: # todo: 缓存 根据大小
72
+ async with AsyncClient(headers=headers or {}, timeout=300) as cilent: # todo: 缓存 根据大小
73
73
  resp = await cilent.get(file)
74
74
  file_bytes = resp.content
75
75
 
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : zhipu_智能体
5
+ # @Time : 2024/12/30 17:34
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description : https://bigmodel.cn/dev/api/intelligent-agent-model/assistantapi
10
+
11
+ from meutils.pipe import *
12
+ from meutils.llm.openai_utils import to_openai_params
13
+ from meutils.llm.clients import AsyncOpenAI, zhipuai_sdk_client
14
+ from meutils.str_utils.regular_expression import parse_url
15
+
16
+ from meutils.schemas.openai_types import chat_completion, chat_completion_chunk, CompletionRequest, CompletionUsage
17
+
18
+
19
+ class Completions(object):
20
+
21
+ def __init__(self,
22
+ base_url: Optional[str] = None,
23
+ api_key: Optional[str] = None
24
+ ):
25
+ pass
26
+
27
+ async def create(self, request: CompletionRequest):
28
+ # attachments = [{"file_id": "chatglm4/3db10f79-a952-4987-83d2-cf0cfd5d5530.pdf"}]
29
+
30
+ chunks = zhipuai_sdk_client.assistant.conversation(
31
+ assistant_id=request.model,
32
+
33
+ model="glm-4-assistant",
34
+ messages=request.messages,
35
+ stream=True,
36
+ attachments=None,
37
+ metadata=None
38
+ )
39
+
40
+ references = {}
41
+ for chunk in chunks:
42
+ # logger.debug(chunk)
43
+ delta = chunk.choices[0].delta
44
+
45
+ if hasattr(delta, "tool_calls") and delta.tool_calls:
46
+ logger.debug(delta.tool_calls)
47
+
48
+ tool_call = delta.tool_calls[0].model_dump()
49
+ tool_type = tool_call.get("type", "") # drawing_tool code_interpreter web_browser retrieval
50
+ outputs = tool_call.get(tool_type, {}).get("outputs") or []
51
+ # references += outputs
52
+
53
+ references.setdefault(tool_type, []).extend(outputs)
54
+
55
+ if not outputs:
56
+ yield f"\n\n> {delta.model_dump_json(indent=4, exclude_none=True)}\n\n"
57
+ logger.debug(references)
58
+
59
+ continue
60
+
61
+ if hasattr(delta, "content"):
62
+ if references:
63
+ for i in self.references2content(references):
64
+ yield i
65
+ references = {}
66
+ # logger.debug(delta.content)
67
+ yield delta.content
68
+
69
+ else:
70
+ logger.debug(delta)
71
+
72
+ # if references: # 搜索
73
+ # urls = [f"[^{i}]: [{ref['title']}]({ref['link']})\n" for i, ref in enumerate(references, 1)]
74
+ #
75
+ # for url in urls:
76
+ # yield url
77
+ #
78
+ # references = []
79
+ #
80
+ # delta = chat_completion_chunk.choices[0].delta.model_construct(**delta.model_dump())
81
+ # chat_completion_chunk.choices[0].delta = delta
82
+ # yield chat_completion_chunk
83
+
84
+ def references2content(self, references):
85
+ """drawing_tool code_interpreter web_browser retrieval"""
86
+ if outputs := references.get("web_browser"):
87
+ for i, ref in enumerate(outputs, 1):
88
+ # yield f"[^{i}]: [{ref['title']}]({ref['link']})\n"
89
+ yield f"[{ref['title']}]({ref['link']})\n"
90
+
91
+ elif outputs := references.get("drawing_tool"):
92
+ for i, ref in enumerate(outputs, 1):
93
+ yield f"![{i}]({ref['image']})\n"
94
+
95
+ yield "\n"
96
+
97
+ async def _create(self, request: CompletionRequest):
98
+ if request.last_user_content.startswith(("http",)):
99
+ file_url, text = request.last_user_content.split(maxsplit=1)
100
+
101
+ request.messages = [
102
+ {
103
+ 'role': 'user',
104
+ 'content': [
105
+ {
106
+ "type": "text",
107
+ "text": text
108
+ },
109
+
110
+ {
111
+ "type": "file", # 不标准
112
+ "file_url": {
113
+ "url": file_url
114
+ }
115
+ }
116
+ ]
117
+ }
118
+ ]
119
+
120
+ logger.debug(request)
121
+
122
+ data = to_openai_params(request)
123
+ return await self.client.chat.completions.create(**data)
124
+
125
+
126
+ if __name__ == '__main__':
127
+ assistant_id = "65940acff94777010aa6b796"
128
+ # assistant_id = "65d2f07bb2c10188f885bd89"
129
+ # assistant_id="65a265419d72d299a9230616",
130
+ # assistant_id="659d051a5f14eb8ce1235b96",
131
+ # assistant_id="65d2f07bb2c10188f885bd89",
132
+
133
+ # assistant_id="659e54b1b8006379b4b2abd6",
134
+ # conversation_id=None, # 多轮:从messages获取
135
+ # conversation_id="67dd1317d7c8fe4c9efe459a",
136
+ request = CompletionRequest(
137
+ model=assistant_id,
138
+ messages=[
139
+ {
140
+ "role": "user",
141
+ "content": [
142
+ {
143
+ "type": "text",
144
+ # "text": "画条狗 输出两张图片",
145
+ # "text": "南京天气如何",
146
+ # "text": "https://sfile.chatglm.cn/chatglm4/3db10f79-a952-4987-83d2-cf0cfd5d5530.pdf 总结这个文件",
147
+
148
+ "text": "https://sfile.chatglm.cn/chatglm4/3db10f79-a952-4987-83d2-cf0cfd5d5530.pdf 基于这个文件做个ppt"
149
+
150
+ # "text": "周杰伦 【最新动态、相关信息或新闻】",
151
+ # "text": "生成PPT"
152
+ }]
153
+ }
154
+ ],
155
+
156
+ # messages=[
157
+ # {
158
+ # "role": "user",
159
+ # "content": [
160
+ # {
161
+ # "type": "text",
162
+ # "text": "基于这个内容做个ppt"
163
+ # },
164
+ # {
165
+ # "type": "file",
166
+ # "file": [
167
+ # {
168
+ # "file_id": "chatglm4/3db10f79-a952-4987-83d2-cf0cfd5d5530.pdf",
169
+ # "file_url": "https://sfile.chatglm.cn/chatglm4/3db10f79-a952-4987-83d2-cf0cfd5d5530.pdf",
170
+ # "file_name": "附件.大模型在合规管理工作中的应用.pdf",
171
+ # "file_size": 2571523,
172
+ # "order": 0,
173
+ # "maxReadPercent": 0,
174
+ # "cover_images": [],
175
+ # "url": "https://sfile.chatglm.cn/chatglm4/3db10f79-a952-4987-83d2-cf0cfd5d5530.pdf"
176
+ # }
177
+ # ]
178
+ # }
179
+ # ]
180
+ # }
181
+ # ]
182
+ )
183
+
184
+ arun(Completions().create(request))
185
+ # 输入 输出
186
+ # input
187
+ # {
188
+ # "assistant_id": "65d2f07bb2c10188f885bd89",
189
+ # "conversation_id": "67d932d5e579c3ded42aa80e",
190
+ # "meta_data": {
191
+ # "if_plus_model": false,
192
+ # "is_test": false,
193
+ # "input_question_type": "xxxx",
194
+ # "channel": "",
195
+ # "draft_id": "",
196
+ # "quote_log_id": "",
197
+ # "platform": "pc"
198
+ # },
199
+ # "messages": [
200
+ # {
201
+ # "role": "user",
202
+ # "content": [
203
+ # {
204
+ # "type": "text",
205
+ # "text": "基于这个内容做个ppt"
206
+ # },
207
+ # {
208
+ # "type": "file",
209
+ # "file": [
210
+ # {
211
+ # "file_id": "chatglm4/3db10f79-a952-4987-83d2-cf0cfd5d5530.pdf",
212
+ # "file_url": "https://sfile.chatglm.cn/chatglm4/3db10f79-a952-4987-83d2-cf0cfd5d5530.pdf",
213
+ # "file_name": "附件.大模型在合规管理工作中的应用.pdf",
214
+ # "file_size": 2571523,
215
+ # "order": 0,
216
+ # "maxReadPercent": 0,
217
+ # "cover_images": [],
218
+ # "url": "https://sfile.chatglm.cn/chatglm4/3db10f79-a952-4987-83d2-cf0cfd5d5530.pdf"
219
+ # }
220
+ # ]
221
+ # }
222
+ # ]
223
+ # }
224
+ # ]
225
+ # }