MeUtils 2025.3.31.19.40.39__py3-none-any.whl → 2025.4.8.18.11.44__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.
Files changed (41) hide show
  1. {MeUtils-2025.3.31.19.40.39.dist-info → MeUtils-2025.4.8.18.11.44.dist-info}/METADATA +264 -264
  2. {MeUtils-2025.3.31.19.40.39.dist-info → MeUtils-2025.4.8.18.11.44.dist-info}/RECORD +41 -27
  3. examples/_openaisdk/openai_ark_bots.py +64 -0
  4. examples/_openaisdk/openai_audio_gpt.py +67 -0
  5. examples/_openaisdk/openai_google.py +129 -77
  6. examples/_openaisdk/openai_kindo.py +1 -1
  7. examples/_openaisdk/zhipu_/346/231/272/350/203/275/344/275/223.py +5 -2
  8. meutils/ai_audio/tts/minimax.py +34 -0
  9. meutils/apis/google_apis/__init__.py +11 -0
  10. meutils/apis/google_apis/audios.py +115 -0
  11. meutils/apis/google_apis/common.py +251 -0
  12. meutils/apis/google_apis/files.py +19 -0
  13. meutils/apis/google_apis/gemini_sdk.py +170 -0
  14. meutils/apis/google_apis/google2openai.py +89 -0
  15. meutils/apis/google_apis/images.py +11 -0
  16. meutils/apis/google_apis/search.py +46 -0
  17. meutils/apis/hailuoai/videos.py +1 -1
  18. meutils/apis/images/google/__init__.py +11 -0
  19. meutils/apis/images/google/images.py +32 -0
  20. meutils/apis/jimeng/images.py +2 -1
  21. meutils/apis/search/ark_web_search.py +69 -0
  22. meutils/apis/search/{web_search.py → zhipu_web_search.py} +21 -30
  23. meutils/apis/textin_apis/common.py +1 -1
  24. meutils/apis/tripo3d/images.py +1 -1
  25. meutils/caches/common.py +4 -2
  26. meutils/data/VERSION +1 -1
  27. meutils/io/files_utils.py +27 -22
  28. meutils/llm/clients.py +6 -5
  29. meutils/llm/completions/assistants/ppt.py +17 -13
  30. meutils/llm/completions/chat_gemini.py +1 -1
  31. meutils/llm/completions/qwenllm.py +8 -2
  32. meutils/llm/openai_utils/common.py +5 -0
  33. meutils/oss/minio_oss.py +38 -8
  34. meutils/oss/minio_utils.py +2 -2
  35. meutils/schemas/oneapi/common.py +23 -6
  36. meutils/schemas/openai_types.py +70 -40
  37. meutils/str_utils/regular_expression.py +6 -3
  38. {MeUtils-2025.3.31.19.40.39.dist-info → MeUtils-2025.4.8.18.11.44.dist-info}/LICENSE +0 -0
  39. {MeUtils-2025.3.31.19.40.39.dist-info → MeUtils-2025.4.8.18.11.44.dist-info}/WHEEL +0 -0
  40. {MeUtils-2025.3.31.19.40.39.dist-info → MeUtils-2025.4.8.18.11.44.dist-info}/entry_points.txt +0 -0
  41. {MeUtils-2025.3.31.19.40.39.dist-info → MeUtils-2025.4.8.18.11.44.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : images
5
+ # @Time : 2025/4/7 13:07
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description : D3
10
+
11
+ from meutils.pipe import *
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : search
5
+ # @Time : 2025/4/2 11:19
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ from meutils.pipe import *
12
+ from google import genai
13
+ from google.genai.types import Tool, GenerateContentConfig, GoogleSearch,HttpOptions
14
+
15
+ client = genai.Client(
16
+ api_key="AIzaSyD19pv1qsYjx4ZKbfH6qvNdYzHMV2TxmPU",
17
+ http_options=HttpOptions(
18
+ base_url="https://all.chatfire.cc/genai"
19
+ )
20
+ )
21
+
22
+
23
+ google_search_tool = Tool(
24
+ google_search=GoogleSearch()
25
+ )
26
+
27
+
28
+ model_id = "gemini-2.0-flash"
29
+
30
+ response = client.models.generate_content(
31
+ model=model_id,
32
+ contents="写一首关于牡丹的诗歌",
33
+ config=GenerateContentConfig(
34
+ tools=[google_search_tool],
35
+ # response_modalities=["TEXT"],
36
+ )
37
+ )
38
+
39
+ for each in response.candidates[0].content.parts:
40
+ print(each.text)
41
+ # Example response:
42
+ # The next total solar eclipse visible in the contiguous United States will be on ...
43
+
44
+ # To get grounding metadata as web content.
45
+ print(response.candidates[0].grounding_metadata.search_entry_point.rendered_content)
46
+ print(response.candidates[0].grounding_metadata.grounding_chunks)
@@ -420,7 +420,7 @@ if __name__ == '__main__': # 304752356930580482
420
420
  # arun(get_task(task_id="307177115102699528", token=token))
421
421
 
422
422
  token = None
423
- token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDQ3MDMwNzIsInVzZXIiOnsiaWQiOiIzMDI4MzM4Njc3NzE5NDkwNTgiLCJuYW1lIjoibWUgYmV0dGVyIiwiYXZhdGFyIjoiIiwiZGV2aWNlSUQiOiIzMDI4MzM3NTk1MTI3NjQ0MTciLCJpc0Fub255bW91cyI6ZmFsc2V9fQ.Mjb64ZjkKyV9pj-_bXyLczU6kU729VLaKbYj9NmrK-4"
423
+ # token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDQ3MDMwNzIsInVzZXIiOnsiaWQiOiIzMDI4MzM4Njc3NzE5NDkwNTgiLCJuYW1lIjoibWUgYmV0dGVyIiwiYXZhdGFyIjoiIiwiZGV2aWNlSUQiOiIzMDI4MzM3NTk1MTI3NjQ0MTciLCJpc0Fub255bW91cyI6ZmFsc2V9fQ.Mjb64ZjkKyV9pj-_bXyLczU6kU729VLaKbYj9NmrK-4"
424
424
  # token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzUxMTcwNzcsInVzZXIiOnsiaWQiOiIzMTEyOTUzMTkzMjc1NzYwNjQiLCJuYW1lIjoiVUdIUiBKVkJYIiwiYXZhdGFyIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUNnOG9jS3RuR2NjdGZsWV9fR2tiQ1MzdnhzSXdWSEFUX0ZmMFdyb3RvMnN4bFdWZW1KMm53PXM5Ni1jIiwiZGV2aWNlSUQiOiIzMTMzMTU5NTMxMDA0MTA4ODciLCJpc0Fub255bW91cyI6ZmFsc2V9fQ.KsRcfnAoPAR08ygzq-GIiujkFbZ2CgLeww7EP9qcb9Q"
425
425
  request = VideoRequest(
426
426
  model="I2V-01-live",
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : __init__.py
5
+ # @Time : 2025/4/1 14:11
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ from meutils.pipe import *
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : images
5
+ # @Time : 2025/4/1 14:11
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+ import os
11
+
12
+ from meutils.pipe import *
13
+ import base64
14
+ from openai import OpenAI
15
+ from PIL import Image
16
+ from io import BytesIO
17
+
18
+ client = OpenAI(
19
+ api_key=os.getenv("GOOGLE_API_KEY"),
20
+ base_url=os.getenv("GOOGLE_BASE_URL"),
21
+ )
22
+
23
+ response = client.images.generate(
24
+ model="imagen-3.0-generate-002",
25
+ prompt="a portrait of a sheepadoodle wearing a cape",
26
+ response_format='b64_json',
27
+ n=1,
28
+ )
29
+ #
30
+ # for image_data in response.data:
31
+ # image = Image.open(BytesIO(base64.b64decode(image_data.b64_json)))
32
+ # image.show()
@@ -50,7 +50,8 @@ async def create_draft_content(request: ImageRequest, token: str):
50
50
 
51
51
  main_component_id = str(uuid.uuid4())
52
52
  if (urls := parse_url(request.prompt)) or image_uri: # 图生 # todo: image base64
53
- request.model = "high_aes_general_v20_L:general_v2.0_L" # 2.1不支持图片编辑 某些不支持
53
+ # request.model = "high_aes_general_v20_L:general_v2.0_L"
54
+ request.model = "high_aes_general_v30l:general_v3.0_18b" # 2.1不支持图片编辑 某些不支持
54
55
 
55
56
  if image_uri:
56
57
  pass
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : ark
5
+ # @Time : 2025/4/1 16:56
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
11
+ from meutils.pipe import *
12
+ from meutils.caches import rcache
13
+
14
+ from meutils.llm.clients import AsyncClient
15
+ from meutils.llm.openai_utils import to_openai_params
16
+
17
+ from meutils.schemas.openai_types import chat_completion, chat_completion_chunk, CompletionRequest, ChatCompletionChunk
18
+
19
+
20
+ class Completions(object):
21
+
22
+ def __init__(self, api_key: Optional[str] = None):
23
+ self.client = AsyncClient(
24
+ api_key=api_key or os.getenv('ARK_BOTS_API_KEY'),
25
+ base_url="https://ark.cn-beijing.volces.com/api/v3/bots",
26
+ )
27
+
28
+ async def create(self, request: CompletionRequest):
29
+ data = to_openai_params(request)
30
+ return await self.client.chat.completions.create(**data)
31
+
32
+ @rcache(noself=True, ttl=15 * 60)
33
+ async def query(self, q: str):
34
+ request = CompletionRequest(
35
+ model="bot-20250401164325-s7945", # todo
36
+
37
+ messages=[
38
+ {"role": "user", "content": q},
39
+ ],
40
+ temperature=0,
41
+ max_tokens=10,
42
+ stream=False,
43
+ )
44
+ completion = await self.create(request)
45
+ logger.debug(completion)
46
+ # print(completion.choices[0].message.content)
47
+
48
+ data = {"data": []}
49
+ if hasattr(completion, "references"):
50
+ data['data'] = completion.references
51
+
52
+ return data
53
+
54
+
55
+ if __name__ == '__main__':
56
+ c = Completions(api_key=os.getenv('ARK_BOTS_API_KEY'))
57
+ # s = c.create(CompletionRequest(
58
+ # model="bot-20250401164325-s7945",
59
+ # messages=[
60
+ # {"role": "user", "content": "今天南京天气如何?"},
61
+ # ],
62
+ # stream=True,
63
+ # ))
64
+ q = "今天有什么热点新闻?"
65
+ q = "今日热点"
66
+
67
+ # arun(c.query("今天南京天气如何?"))
68
+
69
+ arun(c.query(q=q))
@@ -6,10 +6,11 @@
6
6
  # @Author : betterme
7
7
  # @WeChat : meutils
8
8
  # @Software : PyCharm
9
- # @Description :
9
+ # @Description :
10
10
 
11
- from aiostream import stream
12
11
  from meutils.pipe import *
12
+ from meutils.caches import rcache
13
+
13
14
  from meutils.async_utils import sync_to_async
14
15
 
15
16
  from meutils.llm.clients import zhipuai_sdk_client
@@ -39,17 +40,17 @@ class Completions(object):
39
40
  def __init__(self, api_key: Optional[str] = None):
40
41
  self.api_key = api_key
41
42
 
42
- @sync_to_async(thread_sensitive=False)
43
- def create(self, request: CompletionRequest):
44
- _ = self._create(request)
45
- for i in _:
46
- print(i)
47
- # return _
43
+ # @rcache(noself=True, ttl=15 * 60)
44
+ @sync_to_async
45
+ def query(self, q: str):
46
+ data = list(self.create(q))
47
+ return {"data": data}
48
+
49
+ def create(self, request: Union[CompletionRequest, str]):
48
50
 
49
- async def search(self, q: str):
50
- return list(self._create(q))
51
+ q = request.last_user_content if isinstance(request, CompletionRequest) else request
52
+ q = f"{q} 【最新动态、相关信息或新闻】"
51
53
 
52
- def _create(self, request: Union[CompletionRequest, str]):
53
54
  chunks = zhipuai_sdk_client.assistant.conversation(
54
55
 
55
56
  assistant_id="659e54b1b8006379b4b2abd6", # 搜索智能体
@@ -62,7 +63,7 @@ class Completions(object):
62
63
  "type": "text",
63
64
  # "text": "北京未来七天气温,做个折线图",
64
65
  # "text": "画条狗"
65
- "text": request.last_user_content if isinstance(request, CompletionRequest) else request,
66
+ "text": q,
66
67
 
67
68
  }]
68
69
  }
@@ -73,14 +74,17 @@ class Completions(object):
73
74
  )
74
75
 
75
76
  references = []
76
- buffer = []
77
77
  for chunk in chunks:
78
+ # logger.debug(chunk)
79
+
78
80
  delta = chunk.choices[0].delta
79
81
  if hasattr(delta, "tool_calls") and delta.tool_calls:
80
82
  tool_call = delta.tool_calls[0].model_dump()
81
83
  # logger.debug(tool_call)
82
84
  tool_type = tool_call.get("type", "") # web_browser
83
85
  references += tool_call.get(tool_type, {}).get("outputs") or [] # title link content
86
+
87
+ # logger.debug(f"references: {references}")
84
88
  continue
85
89
 
86
90
  if isinstance(request, CompletionRequest):
@@ -89,16 +93,6 @@ class Completions(object):
89
93
  yield from urls
90
94
  references = []
91
95
 
92
- # logger.debug(delta)
93
- # if delta.content.startswith('【') or buffer: # hasattr(delta, "content")
94
- # buffer.append(delta.content)
95
- # if len(buffer) < 20:
96
- # continue
97
- #
98
- # if delta.content.endswith('】'):
99
- # delta.content = convert_citations(''.join(buffer))
100
- # if len(buffer) > 25: buffer = []
101
-
102
96
  delta = chat_completion_chunk.choices[0].delta.model_construct(**delta.model_dump())
103
97
  chat_completion_chunk.choices[0].delta = delta
104
98
  yield chat_completion_chunk
@@ -109,24 +103,21 @@ class Completions(object):
109
103
 
110
104
 
111
105
  if __name__ == '__main__':
112
- model = "web-search-pro"
113
- # model = "tencent-search"
114
-
115
106
  request = CompletionRequest(
116
107
  # model="baichuan4-turbo",
117
108
  # model="xx",
118
109
  # model="deepseek-r1",
119
110
  # model="deepseek-r1:1.5b",
120
- model=model,
111
+ model="model",
121
112
 
122
113
  # model="moonshot-v1-8k",
123
114
  # model="doubao",
124
115
 
125
116
  messages=[
126
- {"role": "user", "content": "《哪吒之魔童闹海》现在的票房是多少"}
117
+ {"role": "user", "content": "周杰伦"}
127
118
  ],
128
119
 
129
120
  stream=True
130
121
  )
131
- # arun(Completions().search('周杰伦'))
132
- arun(Completions().create(request))
122
+ # arun(Completions().create(request))
123
+ # arun(Completions().query(request.last_user_content))
@@ -57,7 +57,7 @@ if __name__ == '__main__':
57
57
  # image = "doc_watermark.jpg"
58
58
 
59
59
  # image = "https://oss.ffire.cc/files/nsfw.jpg"
60
- image = "https://oss.ffire.cc/files/kling_watermark.png" # 无水印
60
+ image = "https://oss.ffire.cc/files/kling_watermark.png" # 无水印
61
61
 
62
62
  request = WatermarkRemove(
63
63
  image=image,
@@ -103,4 +103,4 @@ if __name__ == '__main__':
103
103
  request = ImageRequest(
104
104
  prompt="一只活泼的柴犬,戴着红白相间的头巾,叼着一根魔法棒,眼睛闪烁着星星,正在表演马戏团特技",
105
105
  )
106
- arun(create_task(request))
106
+ arun(create_task(request)) # 60*100
meutils/caches/common.py CHANGED
@@ -18,6 +18,8 @@ cache = memory_cache = cached
18
18
 
19
19
  def rcache(**kwargs):
20
20
  """serializer="pickle"
21
+
22
+ noself: bool = False,
21
23
  :param endpoint: str with the endpoint to connect to. Default is "127.0.0.1".
22
24
  :param port: int with the port to connect to. Default is 6379.
23
25
  :param db: int indicating database to use. Default is 0.
@@ -56,8 +58,8 @@ if __name__ == '__main__':
56
58
  return a
57
59
 
58
60
 
59
- @cache(ttl=3)
60
- @rcache(ttl=2)
61
+ # @cache(ttl=3)
62
+ @rcache(ttl=10)
61
63
  async def mfn(a):
62
64
  logger.debug(a)
63
65
  return a
meutils/data/VERSION CHANGED
@@ -1 +1 @@
1
- 2025.03.31.19.40.39
1
+ 2025.04.08.18.11.44
meutils/io/files_utils.py CHANGED
@@ -14,7 +14,8 @@ import shortuuid
14
14
 
15
15
  from meutils.pipe import *
16
16
  from meutils.decorators.retry import retrying
17
- from meutils.caches.redis_cache import cache
17
+ from meutils.caches import rcache, cache
18
+ from meutils.oss.minio_oss import Minio
18
19
 
19
20
  # from fastapi import UploadFile 有点区别
20
21
  from starlette.datastructures import UploadFile
@@ -49,6 +50,7 @@ def base64_to_bytes(base64_image_string):
49
50
 
50
51
 
51
52
  @retrying()
53
+ @rcache(ttl=300, serializer='pickle') # todo: UploadFile不一定兼容
52
54
  async def to_bytes(
53
55
  file: Union[UploadFile, str, bytes],
54
56
  headers: Optional[dict] = None
@@ -73,7 +75,7 @@ async def to_bytes(
73
75
  elif isinstance(file, str) and file.startswith('http'): # url
74
76
  logger.debug(f"FileType: HTTP")
75
77
 
76
- async with AsyncClient(headers=headers or {}, timeout=60) as cilent:
78
+ async with AsyncClient(headers=headers or {}, timeout=100) as cilent:
77
79
  resp = await cilent.get(file)
78
80
  file_bytes = resp.content
79
81
 
@@ -139,33 +141,34 @@ async def to_url_fal(
139
141
 
140
142
 
141
143
  async def to_url(
142
- file: Union[UploadFile, str, bytes],
144
+ file: Union[str, bytes, List],
143
145
  filename: Optional[str] = None,
144
146
  headers: Optional[dict] = None,
145
- content_type: Optional[str] = "image/png" # todo: 适配 mime_type = "application/octet-stream"
147
+
148
+ content_type: Optional[str] = None,
149
+ mime_type: Optional[str] = None
146
150
  ):
147
- """对象存储"""
148
- if not file: return
151
+ if isinstance(file, list):
152
+ tasks = [to_url(_, f"{shortuuid.random()}_{filename}", headers) for _ in file]
153
+ urls = await asyncio.gather(*tasks)
154
+ return urls
149
155
 
150
- from openai.types.file_object import FileObject
151
- from meutils.oss.minio_oss import Minio
152
- uploads = [partial(Minio().put_object_for_openai, filename=filename, content_type=content_type)]
156
+ if not file: return
153
157
 
154
- for upload in uploads:
155
- try:
156
- file = await to_bytes(file, headers=headers)
157
- url = await upload(file)
158
- if isinstance(url, FileObject):
159
- url = url.filename
160
- return url
161
- except Exception as e:
162
- logger.error(e)
158
+ content_type = content_type or mime_type
159
+ file = await to_bytes(file, headers=headers)
160
+ file_url = await Minio().upload(file, filename, content_type=content_type)
161
+ return file_url
163
162
 
164
163
 
165
- async def to_base64(file: Union[UploadFile, str, bytes, list]):
164
+ async def to_base64(file: Union[UploadFile, str, bytes, list], content_type: Optional[str] = None):
166
165
  if not file: return
167
166
 
168
167
  _ = base64.b64encode(await to_bytes(file)).decode('utf-8')
168
+
169
+ if content_type: # "image/png"
170
+ _ = f"data:{content_type};base64,{_}"
171
+
169
172
  return _
170
173
 
171
174
 
@@ -256,10 +259,12 @@ if __name__ == '__main__':
256
259
  # content_type=None))
257
260
 
258
261
  # arun(to_url_fal(url))
259
- print(guess_mime_type("base64xxxxxxxxxxxxxxxxxx.mp4"))
262
+ # print(guess_mime_type(b"base64xxxxxxxxxxxxxxxxxx.mp4"))
260
263
 
261
- # arun(to_url(Path('img_1.png').read_bytes()))
264
+ # arun(to_url([Path('img_1.png').read_bytes()], filename='x.png'))
265
+ file = "/Users/betterme/PycharmProjects/AI/ppt.txt"
266
+ # arun(to_url(Path(file).read_bytes(), filename='ppt.txt'))
262
267
 
263
268
  # arun(markdown_base64_to_url("![Image_0](data:image)"))
264
269
 
265
-
270
+ arun(to_bytes("https://oss.ffire.cc/files/kling_watermark.png"))
meutils/llm/clients.py CHANGED
@@ -33,16 +33,17 @@ zhipuai_sdk_client = ZhipuAI(
33
33
  base_url=os.getenv("ZHIPUAI_BASE_URL")
34
34
  )
35
35
 
36
-
37
-
38
-
39
-
40
-
41
36
  # zhipuai_client = OpenAI(
42
37
  # api_key=os.getenv("ZHIPUAI_API_KEY"),
43
38
  # base_url=os.getenv("ZHIPUAI_BASE_URL")
44
39
  # )
45
40
 
41
+ # ark_bots_client = AsyncOpenAI(
42
+ # api_key=os.getenv("ZHIPUAI_API_KEY"),
43
+ # base_url="https://ark.cn-beijing.volces.com/api/v3/bots"
44
+ # )
45
+
46
+
46
47
  if __name__ == '__main__':
47
48
  from meutils.pipe import *
48
49
 
@@ -49,6 +49,8 @@ class Completions(object):
49
49
  }
50
50
  ]
51
51
 
52
+ logger.debug(request)
53
+
52
54
  data = to_openai_params(request)
53
55
  return await self.client.chat.completions.create(**data)
54
56
 
@@ -59,19 +61,21 @@ if __name__ == '__main__':
59
61
  "messages": [
60
62
  {
61
63
  "role": "user",
62
- "content": [
63
- {
64
- "type": "file",
65
- "file_url": {
66
- "url": "https://mj101-1317487292.cos.ap-shanghai.myqcloud.com/ai/test.pdf"
67
- }
68
- },
69
- {
70
- "type": "text",
71
- # "text": "基于内容写个ppt给我"
72
- "text": "生成PPT"
73
- }
74
- ]
64
+
65
+ "content": "https://s3.ffire.cc/cdn/20250403/6MxhHmxeX7Z7WYMb8QWqfp_ppt 基于文件做个ppt"
66
+ # "content": [
67
+ # {
68
+ # "type": "file",
69
+ # "file_url": {
70
+ # "url": "https://mj101-1317487292.cos.ap-shanghai.myqcloud.com/ai/test.pdf"
71
+ # }
72
+ # },
73
+ # {
74
+ # "type": "text",
75
+ # # "text": "基于内容写个ppt给我"
76
+ # "text": "生成PPT"
77
+ # }
78
+ # ]
75
79
  }
76
80
  ],
77
81
  # "stream": false
@@ -33,7 +33,7 @@ class Completions(object):
33
33
  api_key: Optional[str] = None
34
34
  ):
35
35
 
36
- base_url = "https://api.aiguoguo199.com/v1"
36
+ base_url = "https://api0.aiguoguo199.com/v1"
37
37
 
38
38
  self.client = AsyncOpenAI(
39
39
  base_url=base_url,
@@ -60,7 +60,9 @@ async def create(request: CompletionRequest, token: Optional[str] = None): # Ch
60
60
  if request.temperature > 1:
61
61
  request.temperature = 1
62
62
 
63
- token = token or await get_next_token_for_polling(feishu_url=FEISHU_URL)
63
+ token = token or await get_next_token_for_polling(feishu_url=FEISHU_URL, from_redis=True)
64
+
65
+ logger.debug(token)
64
66
 
65
67
  client = AsyncOpenAI(
66
68
  base_url=base_url,
@@ -81,6 +83,9 @@ async def create(request: CompletionRequest, token: Optional[str] = None): # Ch
81
83
  request.model = "qwen-max-latest"
82
84
  request.messages[-1]['feature_config'] = {"thinking_enabled": True}
83
85
 
86
+ if "omni" in model:
87
+ request.max_tokens = 2048
88
+
84
89
  # 多模态: todo
85
90
  # if any(i in request.model.lower() for i in ("-vl", "qvq")):
86
91
  # # await to_file
@@ -180,7 +185,8 @@ if __name__ == '__main__':
180
185
  # model="qwen-turbo-2024-11-01",
181
186
  # model="qwen-max-latest",
182
187
  # model="qvq-max-2025-03-25",
183
- model="qvq-72b-preview-0310",
188
+ # model="qvq-72b-preview-0310",
189
+ model="qwen2.5-omni-7b",
184
190
 
185
191
  # model="qwen-max-latest-search",
186
192
  # model="qwq-max",
@@ -62,6 +62,11 @@ def to_openai_params(
62
62
  data['extra_body'] = extra_body # 拓展字段
63
63
  data['model'] = redirect_model or data['model']
64
64
 
65
+ if request.model.startswith(("gemini",)):
66
+ data.pop("extra_body", None)
67
+ data.pop("presence_penalty", None)
68
+ data.pop("frequency_penalty", None)
69
+
65
70
  return data
66
71
 
67
72
 
meutils/oss/minio_oss.py CHANGED
@@ -11,6 +11,7 @@ import datetime
11
11
  import mimetypes
12
12
 
13
13
  from meutils.pipe import *
14
+
14
15
  from minio import Minio as _Minio
15
16
  from openai.types.file_object import FileObject
16
17
  from fastapi import APIRouter, File, UploadFile, Query, Form, BackgroundTasks, Depends, HTTPException, Request, status
@@ -23,7 +24,7 @@ class Minio(_Minio):
23
24
  access_key: Optional[str] = None,
24
25
  secret_key: Optional[str] = None,
25
26
  **kwargs):
26
- self.endpoint = endpoint or os.getenv('MINIO_ENDPOINT', 'oss.ffire.cc') # 默认国内 oss.ffire.cn
27
+ self.endpoint = endpoint or os.getenv('MINIO_ENDPOINT', 's3.ffire.cc')
27
28
  access_key = access_key or os.getenv('MINIO_ACCESS_KEY', 'minio')
28
29
  secret_key = secret_key or os.getenv('MINIO_SECRET_KEY')
29
30
 
@@ -35,6 +36,35 @@ class Minio(_Minio):
35
36
  # super().list_buckets()
36
37
  # super().list_objects('中职职教高考政策解读.pdf')
37
38
  # return super().list_buckets()
39
+ async def upload(
40
+ self,
41
+ file: bytes,
42
+ filename: Optional[str] = None,
43
+
44
+ content_type: Optional[str] = None,
45
+
46
+ bucket_name: str = "cdn",
47
+
48
+ ):
49
+ file_name = filename or shortuuid.random()
50
+
51
+ content_type = (
52
+ content_type
53
+ or mimetypes.guess_type(file_name)[0]
54
+ or "application/octet-stream"
55
+ )
56
+
57
+ object_name = f"""{datetime.datetime.now().strftime("%Y%m%d")}/{file_name}"""
58
+ _ = await self.aput_object(
59
+ bucket_name,
60
+ object_name=object_name,
61
+ content_type=content_type,
62
+
63
+ data=io.BytesIO(file),
64
+ length=len(file),
65
+ )
66
+
67
+ return f"https://{self.endpoint}/{bucket_name}/{object_name}"
38
68
 
39
69
  async def put_object_for_openai(
40
70
  self,
@@ -89,7 +119,7 @@ class Minio(_Minio):
89
119
  )
90
120
 
91
121
  logger.debug(f"content_type: {content_type}")
92
- object_name = f"""{datetime.datetime.now().strftime("%Y-%m-%d")}/{file_name}"""
122
+ object_name = f"""{datetime.datetime.now().strftime("%Y%m%d")}/{file_name}"""
93
123
  _ = await self.aput_object(
94
124
  bucket_name,
95
125
  object_name=object_name,
@@ -177,10 +207,10 @@ if __name__ == '__main__':
177
207
  # )
178
208
  # print(arun(_, debug=True))
179
209
 
180
- _ = client.put_object_for_openai(
181
- url,
182
- filename='cff.png'
183
- )
184
- arun(_)
185
-
210
+ # _ = client.put_object_for_openai(
211
+ # url,
212
+ # filename='cff.png'
213
+ # )
214
+ # arun(_)
186
215
 
216
+ f = client.upload(Path("/Users/betterme/PycharmProjects/AI/qun.png").read_bytes(), filename='x.png')
@@ -14,7 +14,7 @@ minioClient = Minio(
14
14
  endpoint=os.getenv('MINIO_ENDPOINT'),
15
15
  access_key=os.getenv('MINIO_ACCESS_KEY'),
16
16
  secret_key=os.getenv('MINIO_SECRET_KEY'),
17
- # secure=False
17
+ # secure=False,
18
18
  )
19
19
 
20
20
  # Make a bucket with the make_bucket API call.
@@ -31,7 +31,7 @@ print(minioClient.list_buckets())
31
31
  # minioClient.fput_object(bucket_name, 'file.py', 'file.py')
32
32
 
33
33
 
34
- minioClient.fput_object(bucket_name, 'x/img','img.png', content_type='image/png')
34
+ # minioClient.fput_object(bucket_name, 'x/img','img.png', content_type='image/png')
35
35
 
36
36
 
37
37
  # url = minioClient.get_presigned_url(