MeUtils 2025.1.4.11.4.46__py3-none-any.whl → 2025.1.10.20.14.42__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 (73) hide show
  1. {MeUtils-2025.1.4.11.4.46.dist-info → MeUtils-2025.1.10.20.14.42.dist-info}/METADATA +28 -28
  2. {MeUtils-2025.1.4.11.4.46.dist-info → MeUtils-2025.1.10.20.14.42.dist-info}/RECORD +71 -63
  3. examples/_openaisdk/openai_chatfire.py +11 -4
  4. examples/_openaisdk/openai_deepinfra.py +1 -1
  5. examples/_openaisdk/openai_images.py +6 -1
  6. examples/_openaisdk/openai_lingyi.py +59 -0
  7. examples/_openaisdk/openai_ppu.py +47 -0
  8. examples/_openaisdk/openai_test.py +2 -2
  9. examples/_openaisdk/openai_together.py +57 -0
  10. examples/_openaisdk/openai_zhipu.py +4 -3
  11. meutils/ai_audio/asr/openai_asr.py +2 -2
  12. meutils/apis/audio/deepinfra.py +2 -2
  13. meutils/apis/chatglm/glm_video_api.py +1 -1
  14. meutils/apis/common.py +5 -1
  15. meutils/apis/hailuoai/videos.py +14 -5
  16. meutils/apis/images/eidt.py +36 -0
  17. meutils/apis/images/gitee_kolors.py +49 -0
  18. meutils/apis/images/recraft.py +24 -6
  19. meutils/apis/niutrans.py +27 -8
  20. meutils/apis/oneapi/utils.py +24 -9
  21. meutils/apis/translator/deeplx.py +4 -3
  22. meutils/apis/vidu/vidu_video.py +6 -5
  23. meutils/caches/redis_cache.py +5 -0
  24. meutils/common.py +1 -0
  25. meutils/config_utils/lark_utils/common.py +0 -1
  26. meutils/data/VERSION +1 -1
  27. meutils/data/oneapi/NOTICE.md +5 -7
  28. meutils/io/files_utils.py +11 -5
  29. meutils/io/image.py +28 -2
  30. meutils/llm/clients.py +38 -0
  31. meutils/llm/completions/agents/file.py +124 -0
  32. meutils/llm/openai_utils/common.py +2 -2
  33. meutils/llm/utils.py +79 -0
  34. meutils/llm/x.py +75 -0
  35. meutils/notice/feishu.py +1 -0
  36. meutils/parsers/__init__.py +10 -0
  37. meutils/parsers/file_parsers.py +107 -0
  38. meutils/schemas/db/oneapi_types.py +3 -0
  39. meutils/schemas/image_types.py +28 -2
  40. meutils/schemas/kuaishou_types.py +1 -1
  41. meutils/schemas/oneapi/common.py +26 -16
  42. meutils/schemas/vidu_types.py +33 -12
  43. meutils/serving/fastapi/exceptions/http_error.py +2 -6
  44. meutils/str_utils/regular_expression.py +29 -6
  45. meutils/llm/completions/agents/files.py +0 -18
  46. meutils/llm/openai_client.py +0 -15
  47. {MeUtils-2025.1.4.11.4.46.dist-info → MeUtils-2025.1.10.20.14.42.dist-info}/LICENSE +0 -0
  48. {MeUtils-2025.1.4.11.4.46.dist-info → MeUtils-2025.1.10.20.14.42.dist-info}/WHEEL +0 -0
  49. {MeUtils-2025.1.4.11.4.46.dist-info → MeUtils-2025.1.10.20.14.42.dist-info}/entry_points.txt +0 -0
  50. {MeUtils-2025.1.4.11.4.46.dist-info → MeUtils-2025.1.10.20.14.42.dist-info}/top_level.txt +0 -0
  51. /meutils/{fileparser → parsers/fileparser}/PDF/346/212/275/345/217/226.py" +0 -0
  52. /meutils/{fileparser → parsers/fileparser}/__init__.py +0 -0
  53. /meutils/{fileparser → parsers/fileparser}/common.py +0 -0
  54. /meutils/{fileparser → parsers/fileparser}/demo.py +0 -0
  55. /meutils/{fileparser → parsers/fileparser}/filetype/__init__.py +0 -0
  56. /meutils/{fileparser → parsers/fileparser}/filetype/__main__.py +0 -0
  57. /meutils/{fileparser → parsers/fileparser}/filetype/filetype.py +0 -0
  58. /meutils/{fileparser → parsers/fileparser}/filetype/helpers.py +0 -0
  59. /meutils/{fileparser → parsers/fileparser}/filetype/match.py +0 -0
  60. /meutils/{fileparser → parsers/fileparser}/filetype/types/__init__.py +0 -0
  61. /meutils/{fileparser → parsers/fileparser}/filetype/types/application.py +0 -0
  62. /meutils/{fileparser → parsers/fileparser}/filetype/types/archive.py +0 -0
  63. /meutils/{fileparser → parsers/fileparser}/filetype/types/audio.py +0 -0
  64. /meutils/{fileparser → parsers/fileparser}/filetype/types/base.py +0 -0
  65. /meutils/{fileparser → parsers/fileparser}/filetype/types/document.py +0 -0
  66. /meutils/{fileparser → parsers/fileparser}/filetype/types/font.py +0 -0
  67. /meutils/{fileparser → parsers/fileparser}/filetype/types/image.py +0 -0
  68. /meutils/{fileparser → parsers/fileparser}/filetype/types/isobmff.py +0 -0
  69. /meutils/{fileparser → parsers/fileparser}/filetype/types/video.py +0 -0
  70. /meutils/{fileparser → parsers/fileparser}/filetype/utils.py +0 -0
  71. /meutils/{fileparser → parsers/fileparser}/filetype.py +0 -0
  72. /meutils/{fileparser → parsers/fileparser}/pdf.py +0 -0
  73. /meutils/{fileparser → parsers/fileparser}//350/241/250/346/240/274/346/212/275/345/217/226.py" +0 -0
@@ -206,20 +206,21 @@ if __name__ == '__main__':
206
206
  # arun(get_credits(token))
207
207
  #
208
208
  d = {
209
- "prompt": "一条可爱的狗跑过来",
210
- # "url": url # failed to save uploads
209
+ "model": 'vidu-1.5',
210
+ "prompt": "这个女人笑起来",
211
+ "url": "https://oss.ffire.cc/files/kling_watermark.png" # failed to save uploads
211
212
  }
212
213
  token = None
213
214
  # print(bjson(ViduRequest(**d).payload))
214
- # arun(create_task(ViduRequest(**d)))
215
+ arun(create_task(ViduRequest(**d)))
215
216
  # arun(create_task(ViduRequest(**d), vip=False))
216
217
  # # pass
217
218
  # token = "sensorsdata2015jssdkcross=dfm-enc-%7B%22Va28a6y8_aV%22%3A%22sSsAAnHAInAGEtIG%22%2C%22gae28_aV%22%3A%22EGEuAnststSEirt-ARSAigSVHIiHVs-EtHsHnIR-sARInAA-EGEuAnststHsIti%22%2C%22OemO2%22%3A%7B%22%24ki8r28_8eiggay_2mbeyr_8cOr%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24ki8r28_2rieyz_lrcMmeV%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24ki8r28_ergreere%22%3A%22%22%7D%2C%22aVr68a8ar2%22%3A%22rc3liZ7ku67OV5kgPsGCiskkDskl3qmawFlJPq0swqfcpXNJPZKSBF0IQXLzWq7lQFQzQZNcBF1SQF3EQqwIBF3MQhwswX08wFlJPq0swqfcpXKcwhzz3aMax9klWZHAiD7HDsJCWskbDskl3qmawqNcwX0sQF0hQq0HwFfhp4xG%22%2C%22za28mec_kmfa6_aV%22%3A%7B%226ior%22%3A%22%24aVr68a8c_kmfa6_aV%22%2C%22Cikbr%22%3A%22sSsAAnHAInAGEtIG%22%7D%7D;_ga=GA1.1.2058758439.1724312077;_ga_ZJBV7VYP55=GS1.1.1727080335.38.1.1727080510.0.0.0;JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgzNTAzODAsImlhdCI6MTcyNzA1NDM4MCwiaXNzIjoiaWFtIiwic3ViIjoiMjQyMDA2NTAzNjA5MTgzOSJ9.PkjQqjYB56vYetYwmlagnWn_6bSCwoxCjI7BjfelBOU;Shunt="
218
219
  # # token = "_ga=GA1.1.2058758439.1724312077; JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgzNTAzODAsImlhdCI6MTcyNzA1NDM4MCwiaXNzIjoiaWFtIiwic3ViIjoiMjQyMDA2NTAzNjA5MTgzOSJ9.PkjQqjYB56vYetYwmlagnWn_6bSCwoxCjI7BjfelBOU; Shunt=; sensorsdata2015jssdkcross=dfm-enc-%7B%22Va28a6y8_aV%22%3A%22sSsAAnHAInAGEtIG%22%2C%22gae28_aV%22%3A%22EGEuAnststSEirt-ARSAigSVHIiHVs-EtHsHnIR-sARInAA-EGEuAnststHsIti%22%2C%22OemO2%22%3A%7B%22%24ki8r28_8eiggay_2mbeyr_8cOr%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24ki8r28_2rieyz_lrcMmeV%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24ki8r28_ergreere%22%3A%22%22%7D%2C%22aVr68a8ar2%22%3A%22rc3liZ7ku67OV5kgPsGCiskkDskl3qmawFlJPq0swqfcpXNJPZKSBF0IQXLzWq7lQFQzQZNcBF1SQF3EQqwIBF3MQhwswX08wFlJPq0swqfcpXKcwhzz3aMax9klWZHAiD7HDsJCWskbDskl3qmawqNcwX0sQF0hQq0HwFfhp4xG%22%2C%22za28mec_kmfa6_aV%22%3A%7B%226ior%22%3A%22%24aVr68a8c_kmfa6_aV%22%2C%22Cikbr%22%3A%22sSsAAnHAInAGEtIG%22%7D%7D; _ga_ZJBV7VYP55=GS1.1.1727080335.38.1.1727080510.0.0.0"
219
220
  # token = "JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjgzNDkyNzQsImlhdCI6MTcyNzA1MzI3NCwiaXNzIjoiaWFtIiwic3ViIjoiMjQyMDg5NjA4MTIwNTkwNyJ9.MRXmSr48PifQgRN1-yTTu8d7Sq1An4OS7G5WoYpJ_PU"
220
221
 
221
- token = "_ga=GA1.1.1191408146.1725443726; Shunt=; JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzY0NzgzODIsImlhdCI6MTczNTE4MjM4MiwiaXNzIjoiaWFtIiwic3ViIjoiMjU3NTg1MzI5MDUyNzYwNiJ9.AJBuQH0B9aQ2znnczYoqBw9YvHkLh0uZF0QQx5xdxrc; sensorsdata2015jssdkcross=dfm-enc-%7B%22Va28a6y8_aV%22%3A%22sHRHtHIsGAHsRnAn%22%2C%22gae28_aV%22%3A%22EGEuyRHVigIEtAG-AGRuSsHrVAGRuS-EtHsHnIR-sARInAA-EGEuyRHVigSEuIR%22%2C%22OemO2%22%3A%7B%22%24ki8r28_8eiggay_2mbeyr_8cOr%22%3A%22%E8%87%AA%E7%84%B6%E6%90%9C%E7%B4%A2%E6%B5%81%E9%87%8F%22%2C%22%24ki8r28_2rieyz_lrcMmeV%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC%22%2C%22%24ki8r28_ergreere%22%3A%22z88O2%3A%2F%2Fiyymb682.fmmfkr.ymo%2F%22%7D%2C%22aVr68a8ar2%22%3A%22rc3liZ7ku67OV5kgPsGCiskkDskl3qmawFlJPowIQZ7zWqwJpX0HBF0HQs3AwqdkWX0HQs3ABF1SQF3EQqwIBF3MQhwswX08wFlJPowIQZ7zWqNJPqwI3aMax9klWZHAiD7HDsJCWskbDskl3qmawqKIQFfEwh3HwXKcQhPMQaxG%22%2C%22za28mec_kmfa6_aV%22%3A%7B%226ior%22%3A%22%24aVr68a8c_kmfa6_aV%22%2C%22Cikbr%22%3A%22sHRHtHIsGAHsRnAn%22%7D%7D; _ga_ZJBV7VYP55=GS1.1.1735182278.4.1.1735182405.26.0.0"
222
- arun(check_token(token))
222
+ # token = "_ga=GA1.1.1191408146.1725443726; Shunt=; JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzY0NzgzODIsImlhdCI6MTczNTE4MjM4MiwiaXNzIjoiaWFtIiwic3ViIjoiMjU3NTg1MzI5MDUyNzYwNiJ9.AJBuQH0B9aQ2znnczYoqBw9YvHkLh0uZF0QQx5xdxrc; sensorsdata2015jssdkcross=dfm-enc-%7B%22Va28a6y8_aV%22%3A%22sHRHtHIsGAHsRnAn%22%2C%22gae28_aV%22%3A%22EGEuyRHVigIEtAG-AGRuSsHrVAGRuS-EtHsHnIR-sARInAA-EGEuyRHVigSEuIR%22%2C%22OemO2%22%3A%7B%22%24ki8r28_8eiggay_2mbeyr_8cOr%22%3A%22%E8%87%AA%E7%84%B6%E6%90%9C%E7%B4%A2%E6%B5%81%E9%87%8F%22%2C%22%24ki8r28_2rieyz_lrcMmeV%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC%22%2C%22%24ki8r28_ergreere%22%3A%22z88O2%3A%2F%2Fiyymb682.fmmfkr.ymo%2F%22%7D%2C%22aVr68a8ar2%22%3A%22rc3liZ7ku67OV5kgPsGCiskkDskl3qmawFlJPowIQZ7zWqwJpX0HBF0HQs3AwqdkWX0HQs3ABF1SQF3EQqwIBF3MQhwswX08wFlJPowIQZ7zWqNJPqwI3aMax9klWZHAiD7HDsJCWskbDskl3qmawqKIQFfEwh3HwXKcQhPMQaxG%22%2C%22za28mec_kmfa6_aV%22%3A%7B%226ior%22%3A%22%24aVr68a8c_kmfa6_aV%22%2C%22Cikbr%22%3A%22sHRHtHIsGAHsRnAn%22%7D%7D; _ga_ZJBV7VYP55=GS1.1.1735182278.4.1.1735182405.26.0.0"
223
+ # arun(check_token(token))
223
224
  #
224
225
  # FEISHU_URL = "https://xchatllm.feishu.cn/sheets/GYCHsvI4qhnDPNtI4VPcdw2knEd?sheet=rxldsA"
225
226
  # FEISHU_URL="https://xchatllm.feishu.cn/sheets/GYCHsvI4qhnDPNtI4VPcdw2knEd?sheet=Hcr2i8"
@@ -11,6 +11,7 @@
11
11
 
12
12
 
13
13
  import hermes.backend.redis
14
+ import hermes.backend.inprocess
14
15
 
15
16
  from meutils.db.redis_db import pool
16
17
 
@@ -19,6 +20,10 @@ cache = hermes.Hermes(
19
20
  connection_pool=pool
20
21
  )
21
22
 
23
+ cache_inmemory = hermes.Hermes(
24
+ backend=hermes.backend.inprocess.Backend,
25
+ )
26
+
22
27
  if __name__ == '__main__':
23
28
  from meutils.pipe import *
24
29
 
meutils/common.py CHANGED
@@ -51,6 +51,7 @@ import toml
51
51
  import yaml
52
52
  import typer
53
53
  import json
54
+ import mimetypes
54
55
  import joblib
55
56
  from joblib.hashing import hash
56
57
  import httpx
@@ -7,7 +7,6 @@
7
7
  # @WeChat : meutils
8
8
  # @Software : PyCharm
9
9
  # @Description : httpx重试 transport = httpx.AsyncHTTPTransport(retries=3) # response.raise_for_status()
10
- import pandas as pd
11
10
 
12
11
  from meutils.pipe import *
13
12
  from meutils.decorators.retry import retrying
meutils/data/VERSION CHANGED
@@ -1 +1 @@
1
- 2025.01.04.11.04.46
1
+ 2025.01.10.20.14.42
@@ -32,16 +32,15 @@
32
32
  </details>
33
33
 
34
34
  <details markdown="1">
35
- <summary><b>预祝大家新年快乐🎁元旦礼物☺</b></summary>
35
+ <summary><b>大额充值优惠</b></summary>
36
36
 
37
- - 联系企微客服
38
- - 充值100-200 增送5%
39
- - 充值200-500 增送10%
40
- - 充值500-1000 增送15%
41
- - 充值1000-2000 增送20%
37
+ - 充值1000-2000 增送10%
42
38
 
43
39
  </details>
44
40
 
41
+ ## 2025-01-04
42
+ - 增加模型配额 gemini-2.0-flash-exp、gemini-2.0-flash-thinking-exp-1219
43
+
45
44
  ## 2024-12-31
46
45
 
47
46
  - 上线新模型
@@ -49,7 +48,6 @@
49
48
  在不显著降低通用任务能力的情况下,在专家任务能力方面表现大幅提升。其在 AIME 2024、MATH500 和 LiveCodeBench 评测中,效果与
50
49
  OpenAI-o1-Preview 相当。
51
50
  - 兼容SparkAI客户端,文件问答&图片问答:baseurl改为`https://api.chatfire.cn/sparkai/v1`
52
- ![](https://sfile.chatglm.cn/chatglm4/e5b99a34-f859-4880-a0ea-a9c6dbc8a60f.png)
53
51
 
54
52
  ## 2024-12-27
55
53
 
meutils/io/files_utils.py CHANGED
@@ -18,6 +18,13 @@ from starlette.datastructures import UploadFile
18
18
  from contextlib import asynccontextmanager
19
19
 
20
20
 
21
+ def guess_mime_type(file):
22
+ mime_type = None
23
+ if isinstance(file, str):
24
+ mime_type, _ = mimetypes.guess_type(file)
25
+ return mime_type or "application/octet-stream"
26
+
27
+
21
28
  def file_append_firstline(line):
22
29
  with open('untitled.txt', "r+") as f:
23
30
  old = f.read()
@@ -37,7 +44,6 @@ def base64_to_bytes(base64_image_string):
37
44
  return base64.b64decode(base64_image_string.split(",", 1)[-1])
38
45
 
39
46
 
40
- @retrying()
41
47
  async def to_bytes(file: Union[UploadFile, str, bytes], headers: Optional[dict] = None): # plus
42
48
  """
43
49
 
@@ -97,11 +103,10 @@ async def to_url_fal(
97
103
  """对象存储"""
98
104
  if not file: return
99
105
 
100
- if file.startswith("http"): # 转存: todo: base64
106
+ if isinstance(file, str) and file.startswith("http"): # 转存: todo: base64
101
107
  content_type = mimetypes.guess_type(file)[0] or content_type
102
108
 
103
- file = await to_bytes(file, headers=headers)
104
-
109
+ file = await to_bytes(file, headers=headers)
105
110
  content_type = (
106
111
  mimetypes.guess_type(filename or '')[0]
107
112
  or mimetypes.guess_type(f"x.{content_type}")[0] # format: image/png
@@ -218,4 +223,5 @@ if __name__ == '__main__':
218
223
  # "https://cdn.hailuoai.video/moss/prod/2024-11-11-09/video/1731287464150180347-video_raw_8ba15c5c206f8d393a9248f4f9215ed8_312186282087260162.mp4",
219
224
  # content_type=None))
220
225
 
221
- arun(to_url_fal(url))
226
+ # arun(to_url_fal(url))
227
+ print(guess_mime_type("base64xxxxxxxxxxxxxxxxxx.png"))
meutils/io/image.py CHANGED
@@ -13,7 +13,31 @@ import mimetypes
13
13
  from PIL import Image, ImageDraw
14
14
 
15
15
  from meutils.pipe import *
16
- from meutils.io.files_utils import to_url
16
+ from meutils.io.files_utils import to_url, to_bytes
17
+
18
+
19
+ async def describe_image(image: Union[str, bytes]):
20
+ """
21
+ 图片转base64
22
+ :param image: 图片路径或图片对象
23
+ :return: base64字符串
24
+ """
25
+ _ = await to_bytes(image)
26
+ img = Image.open(io.BytesIO(_))
27
+
28
+ info = {
29
+ 'format': img.format, # 图片格式
30
+ 'mode': img.mode, # 颜色模式
31
+
32
+ 'width': img.width, # 宽度
33
+ 'height': img.height, # 高度
34
+ 'size': img.size, # (宽度, 高度)
35
+
36
+ 'is_animated': getattr(img, 'is_animated', False), # 是否是动图
37
+ 'n_frames': getattr(img, 'n_frames', 1), # 帧数
38
+ 'info': img.info, # 图片附加信息
39
+ }
40
+ return info
17
41
 
18
42
 
19
43
  def crop_polygon(image: Union[str, bytes], outline_points, inline_points):
@@ -199,4 +223,6 @@ if __name__ == '__main__':
199
223
 
200
224
  url = "https://s22-def.ap4r.com/bs2/upload-ylab-stunt-sgp/se/ai_portal_sgp_queue_mmu_img2img_aiweb/7de17faa-cc11-48a6-b94a-e80fe7a34841/1.png"
201
225
 
202
- arun(image2nowatermark_image(url, picinfo=PICINFO2_RIGHT_BOTTOM))
226
+ # arun(image2nowatermark_image(url, picinfo=PICINFO2_RIGHT_BOTTOM))
227
+ with timer():
228
+ arun(describe_image("https://oss.ffire.cc/files/kling_watermark.png"))
meutils/llm/clients.py ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : chat
5
+ # @Time : 2024/8/19 14:23
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+ from openai import Client, AsyncClient, AsyncStream, APIStatusError
11
+
12
+ from meutils.pipe import *
13
+
14
+ OpenAI = lru_cache(Client)
15
+ AsyncOpenAI = lru_cache(AsyncClient)
16
+
17
+ moonshot_client = AsyncOpenAI(
18
+ api_key=os.getenv("MOONSHOT_API_KEY"),
19
+ base_url=os.getenv("MOONSHOT_BASE_URL")
20
+ )
21
+ zhipuai_client = AsyncOpenAI(
22
+ api_key=os.getenv("ZHIPUAI_API_KEY"),
23
+ base_url=os.getenv("ZHIPUAI_BASE_URL")
24
+ )
25
+
26
+ if __name__ == '__main__':
27
+ from meutils.pipe import *
28
+
29
+ # OpenAI().chat.completions.create(messages=[{"role": "user", "content": "hi"}], model='glm-4-flash')
30
+
31
+ # arun(zhipuai_client.chat.completions.create(messages=[{"role": "user", "content": "hi"}], model='glm-4-flash'))
32
+
33
+ # web-search-pro
34
+
35
+ arun(zhipuai_client.chat.completions.create(
36
+ messages=[{"role": "user", "content": "中国队奥运会拿了多少奖牌"}],
37
+ model='web-search-pro')
38
+ )
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : files
5
+ # @Time : 2025/1/3 15:38
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description : 支持文档、图片、音频、视频问答
10
+ """单一智能体
11
+ 任意模型支持文档、图片、音频、视频问答
12
+ api形式
13
+ - /agents/v1
14
+ - /v1 前缀区分 agents-{model}【底层调用 /agents/v1】
15
+
16
+ """
17
+
18
+ from meutils.pipe import *
19
+ from meutils.parsers.file_parsers import file_extract
20
+
21
+ from meutils.llm.clients import AsyncOpenAI
22
+ from meutils.llm.openai_utils import to_openai_params
23
+
24
+ from meutils.str_utils.regular_expression import parse_url
25
+
26
+ from meutils.schemas.openai_types import chat_completion, chat_completion_chunk, ChatCompletionRequest, CompletionUsage
27
+
28
+
29
+ class Completions(object):
30
+
31
+ def __init__(self, api_key: Optional[str] = None):
32
+ self.api_key = api_key
33
+
34
+ async def create(self, request: ChatCompletionRequest):
35
+ """[{'role': 'user', 'content': 'hi'}]
36
+ {"type": "file_url", "file_url": {"url": "https://oss.ffire.cc/files/招标文件备案表(第二次).pdf", "detai": "auto"}}"""
37
+
38
+ if urls := parse_url(str(request.messages)):
39
+ logger.debug(urls)
40
+
41
+ file_reponse = await file_extract(urls[-1])
42
+ if file_reponse: # 仅关注最后一个
43
+ request.system_messages.append({
44
+ "role": "system",
45
+ "content": json.dumps(file_reponse, ensure_ascii=False),
46
+ })
47
+
48
+ request.messages = request.system_messages + request.messages
49
+
50
+ logger.debug(request)
51
+
52
+ data = to_openai_params(request)
53
+ return await AsyncOpenAI(api_key=self.api_key).chat.completions.create(**data)
54
+
55
+
56
+ # data: {"event": "message", "task_id": "900bbd43-dc0b-4383-a372-aa6e6c414227", "id": "663c5084-a254-4040-8ad3-51f2a3c1a77c", "answer": "Hi", "created_at": 1705398420}\n\n
57
+ if __name__ == '__main__':
58
+ c = Completions()
59
+
60
+ request = ChatCompletionRequest(
61
+ # model="qwen-turbo-2024-11-01",
62
+ # model="claude-3-5-sonnet-20241022",
63
+ model="gpt-4o-mini",
64
+
65
+ messages=[
66
+ {
67
+ 'role': 'system',
68
+ 'content': '你是一个文件问答助手'
69
+ },
70
+ # {
71
+ # 'role': 'user',
72
+ # # 'content': {
73
+ # # "type": "file_url",
74
+ # # "file_url": {"url": "https://oss.ffire.cc/files/招标文件备案表(第二次).pdf", "detai": "auto"}
75
+ # # },
76
+ # 'content': [
77
+ # {
78
+ # "type": "text",
79
+ # "text": "这个文件讲了什么?"
80
+ # },
81
+ # # 多轮的时候要剔除
82
+ # {
83
+ # "type": "file_url",
84
+ # "file_url": {"url": "https://oss.ffire.cc/files/招标文件备案表(第二次).pdf", "detai": "auto"}
85
+ # }
86
+ # ]
87
+ # },
88
+
89
+ {
90
+ 'role': 'user',
91
+ # 'content': {
92
+ # "type": "file_url",
93
+ # "file_url": {"url": "https://oss.ffire.cc/files/招标文件备案表(第二次).pdf", "detai": "auto"}
94
+ # },
95
+ # 'content': "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 这个文件讲了什么?",
96
+ # 'content': "https://translate.google.com/?sl=zh-CN&tl=en&text=%E6%8F%90%E4%BE%9B%E6%96%B9&op=tr1anslate 这个文件讲了什么?",
97
+
98
+ "content": "总结下 https://oss.ffire.cc/files/百炼系列手机产品介绍.docx"
99
+
100
+ },
101
+
102
+ # {'role': 'assistant', 'content': "好的"},
103
+ # {
104
+ # 'role': 'user',
105
+ # # 'content': {
106
+ # # "type": "file_url",
107
+ # # "file_url": {"url": "https://oss.ffire.cc/files/招标文件备案表(第二次).pdf", "detai": "auto"}
108
+ # # },
109
+ # 'content': [
110
+ # {
111
+ # "type": "text",
112
+ # "text": "错了 继续回答"
113
+ # },
114
+ # # {
115
+ # # "type": "file_url",
116
+ # # "file_url": {"url": "https://oss.ffire.cc/files/招标文件备案表(第二次).pdf", "detai": "auto"}
117
+ # # }
118
+ # ]
119
+ # }
120
+ ]
121
+
122
+ )
123
+
124
+ arun(c.create(request))
@@ -7,11 +7,11 @@
7
7
  # @WeChat : meutils
8
8
  # @Software : PyCharm
9
9
  # @Description :
10
- import time
11
10
 
12
11
  import tiktoken
13
12
  from contextlib import asynccontextmanager
14
13
  from openai import AsyncOpenAI, OpenAI, AsyncStream
14
+ from meutils.llm.clients import AsyncOpenAI, OpenAI, AsyncStream
15
15
 
16
16
  from meutils.pipe import *
17
17
  from meutils.async_utils import achain, async_to_sync
@@ -266,7 +266,7 @@ if __name__ == '__main__':
266
266
  with timer():
267
267
  try:
268
268
  async with ppu_flow(api_key="sk-OYK4YxtTlWauT2TdGR5FTAJpkRmSnDwPly4cve0cAvMcrBkZ", post="api-oss",
269
- n=100):
269
+ n=1):
270
270
  logger.debug("消费了哦")
271
271
 
272
272
  except Exception as e:
meutils/llm/utils.py CHANGED
@@ -8,7 +8,66 @@
8
8
  # @Software : PyCharm
9
9
  # @Description :
10
10
 
11
+ from contextlib import asynccontextmanager
12
+
11
13
  from meutils.pipe import *
14
+ from meutils.llm.clients import AsyncOpenAI, OpenAI, AsyncStream
15
+ from meutils.schemas.oneapi import MODEL_PRICE
16
+ from meutils.notice.feishu import send_message
17
+ from meutils.apis.oneapi.utils import get_user_quota
18
+
19
+
20
+ async def ppu(
21
+ model: str = 'ppu',
22
+ api_key: Optional[str] = None,
23
+ base_url: Optional[str] = None,
24
+ ):
25
+ if model not in MODEL_PRICE:
26
+ send_message(f"模型未找到{model},ppu-1默认", title=__name__)
27
+ model = "ppu-1"
28
+
29
+ client = AsyncOpenAI(api_key=api_key, base_url=base_url)
30
+ r = await client.chat.completions.create(messages=[{'role': 'user', 'content': 'hi'}], model=model)
31
+
32
+
33
+ @asynccontextmanager
34
+ async def ppu_flow(
35
+ api_key: str,
36
+ base_url: Optional[str] = None,
37
+
38
+ model: str = "ppu-1", # 后计费
39
+
40
+ n: float = 1, # 计费次数
41
+
42
+ **kwargs
43
+ ):
44
+ """
45
+ 查余额
46
+ 失败,先扣费
47
+ 成功,充足,后扣费
48
+ 成功,不足,报错
49
+ """
50
+ n = int(np.ceil(n)) # 0 不计费
51
+
52
+ if n: # 计费
53
+ try:
54
+ money = await get_user_quota(api_key)
55
+ logger.debug(f"PREPAY: USER 余额 {money}")
56
+ except Exception as e:
57
+ logger.error(e)
58
+ money = None
59
+
60
+ if money and money > MODEL_PRICE.get(model, 0.1):
61
+ yield # 先执行
62
+
63
+ # 执行计费逻辑
64
+ await asyncio.gather(*[ppu(model, api_key=api_key, base_url=base_url) for _ in range(n)])
65
+
66
+ if money is None:
67
+ yield # 后执行
68
+
69
+ else: # 不计费
70
+ yield
12
71
 
13
72
 
14
73
  def oneturn2multiturn(messages, template: Optional[str] = None):
@@ -52,3 +111,23 @@ def oneturn2multiturn(messages, template: Optional[str] = None):
52
111
  context += f"{role}:\n{content}\n\n"
53
112
  context += "assistant:\n"
54
113
  return context
114
+
115
+
116
+ if __name__ == '__main__':
117
+ async def main():
118
+ with timer():
119
+ try:
120
+ async with ppu_flow(
121
+ api_key="sk-OYK4YxtTlWauT2TdGR5FTAJpkRmSnDwPly4cve0cAvMcrBkZ",
122
+ model="api-oss",
123
+ n=1):
124
+ logger.debug("消费了哦")
125
+
126
+ except Exception as e:
127
+ pass
128
+ logger.error(e)
129
+ # logger.debug(e.response.status_code)
130
+ # logger.debug(e.response.text)
131
+
132
+
133
+ arun(main())
meutils/llm/x.py ADDED
@@ -0,0 +1,75 @@
1
+ import os
2
+
3
+ # !/usr/bin/env python
4
+ # -*- coding: utf-8 -*-
5
+ # @Project : AI. @by PyCharm
6
+ # @File : x
7
+ # @Time : 2025/1/7 17:31
8
+ # @Author : betterme
9
+ # @WeChat : meutils
10
+ # @Software : PyCharm
11
+ # @Description :
12
+
13
+ from meutils.pipe import *
14
+ from meutils.llm.clients import zhipuai_client
15
+ from meutils.schemas.openai_types import _ChatCompletion
16
+
17
+ import requests
18
+ import uuid
19
+
20
+ api_key = os.getenv("ZHIPUAI_API_KEY")
21
+
22
+ msg = [
23
+ {
24
+ "role": "user",
25
+ "content": "中国队奥运会拿了多少奖牌"
26
+ }
27
+ ]
28
+
29
+ tool = "web-search-pro"
30
+
31
+
32
+ async def run_v4_sync():
33
+ url = "https://open.bigmodel.cn/api/paas/v4/tools"
34
+ request_id = str(uuid.uuid4())
35
+ data = {
36
+ "request_id": request_id,
37
+ "tool": tool,
38
+ "stream": False,
39
+ "messages": msg
40
+ }
41
+
42
+ # resp = requests.post(
43
+ # url,
44
+ # json=data,
45
+ # headers={'Authorization': api_key},
46
+ # timeout=300
47
+ # )
48
+ # print(resp.content.decode())
49
+
50
+ resp = await zhipuai_client.post(
51
+ "/tools",
52
+ body={
53
+ "request_id": str(uuid.uuid4()),
54
+ "tool": tool,
55
+ "stream": False,
56
+ "messages": msg
57
+ },
58
+ cast_to=object
59
+ )
60
+ return resp
61
+
62
+
63
+ file_object = zhipuai_client.files.create(file=Path("/Users/betterme/PycharmProjects/AI/MeUtils/meutils/llm/completions/rag/百炼系列手机产品介绍.docx"), purpose="file-extract")
64
+
65
+
66
+
67
+ if __name__ == '__main__':
68
+ # r = arun(run_v4_sync())
69
+ # arun(file_object)
70
+
71
+ file_id = "1736243045_3771f3dfb394424885f24c3dc0583741"
72
+
73
+ file_content = json.loads(zhipuai_client.files.content(file_id=file_id).content)["content"]
74
+
75
+ file_content = json.loads(r.content)["content"]
meutils/notice/feishu.py CHANGED
@@ -19,6 +19,7 @@ LLM_REVERSE = "https://open.feishu.cn/open-apis/bot/v2/hook/cd5c9126-a882-4a24-9
19
19
  Vison = ""
20
20
  # AUDIOS_TTS = "https://open.feishu.cn/open-apis/bot/v2/hook/ff7d4b86-d238-436c-9447-f88cf603454d"
21
21
  AUDIO = "https://open.feishu.cn/open-apis/bot/v2/hook/80c2a700-adfa-4b9b-8e3f-00b78f2f5c8b"
22
+ FILES = "https://open.feishu.cn/open-apis/bot/v2/hook/075fb2fa-a559-4a7e-89ac-3ab9934ff15c"
22
23
 
23
24
 
24
25
  @background_task
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : __init__.py
5
+ # @Time : 2025/1/10 15:45
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description :
10
+
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ # @Project : AI. @by PyCharm
4
+ # @File : fileparser
5
+ # @Time : 2025/1/7 17:48
6
+ # @Author : betterme
7
+ # @WeChat : meutils
8
+ # @Software : PyCharm
9
+ # @Description : https://bigmodel.cn/dev/activities/freebie/fileextracion
10
+ import asyncio
11
+
12
+ from meutils.pipe import *
13
+ from meutils.io.files_utils import to_bytes, guess_mime_type
14
+ from meutils.llm.clients import moonshot_client, zhipuai_client, APIStatusError
15
+ from meutils.notice.feishu import send_message as _send_message, FILES
16
+ from meutils.caches.redis_cache import cache
17
+
18
+ send_message = partial(
19
+ _send_message,
20
+ title=__name__,
21
+ url=FILES
22
+ )
23
+ """
24
+
25
+ # 智谱
26
+ # 格式限制:.PDF .DOCX .DOC .XLS .XLSX .PPT .PPTX .PNG .JPG .JPEG .CSV .PY .TXT .MD .BMP .GIF
27
+
28
+ # kimi todo: 定期删除文件
29
+ 文件接口与 Kimi 智能助手中上传文件功能所使用的相同,支持相同的文件格式,它们包括
30
+ .pdf .txt .csv .doc .docx .xls .xlsx .ppt .pptx .md .jpeg .png .bmp .gif .svg .svgz .webp .ico .xbm .dib .pjp .tif
31
+ .pjpeg .avif .dot .apng .epub .tiff .jfif .html .json .mobi .log .go .h .c .cpp .cxx .cc .cs .java .js .css .jsp .php
32
+ .py .py3 .asp .yaml .yml .ini .conf .ts .tsx 等格式。
33
+
34
+ """
35
+
36
+
37
+ @cache(ttl=24 * 3600)
38
+ async def file_extract(
39
+ file,
40
+ provider: Union[str, Literal['kimi', 'moonshot', 'zhipu']] = 'moonshot'
41
+ ):
42
+ """todo 定时删除文件
43
+ todo: 兼容下 url bytes path
44
+
45
+ # moonshot_client.files.
46
+
47
+ # len(moonshot_client.files.list().data)
48
+
49
+ """
50
+ mime_type = guess_mime_type(file)
51
+ if mime_type == "application/octet-stream": return # 不解析
52
+
53
+ logger.debug(f"file_extract: {mime_type}")
54
+
55
+ if provider == "zhipu":
56
+ client = zhipuai_client
57
+ else:
58
+ client = moonshot_client # 默认
59
+
60
+ filename = Path(file).name
61
+ file_bytes: bytes = await to_bytes(file)
62
+
63
+ # todo: zhipu兜底
64
+ try:
65
+ file_object = await client.files.create(
66
+ # file=file,
67
+ # file=("filename.pdf", file),
68
+ file=(filename, file_bytes, mime_type),
69
+ purpose="file-extract"
70
+ )
71
+
72
+ if file_object.status and file_object.status != "ok":
73
+ if isinstance(file, str) and file.startswith('http'):
74
+ file_object.url = file
75
+ send_message(file_object)
76
+
77
+ response = await client.files.content(file_id=file_object.id) # 抛错处理
78
+ return response.json()
79
+ except APIStatusError as e:
80
+ logger.debug(e)
81
+ _ = e.response.json()
82
+ if isinstance(file, str) and file.startswith('http'):
83
+ _['url'] = file
84
+ send_message(_)
85
+ return _
86
+
87
+
88
+ if __name__ == '__main__':
89
+ # file = "https://oss.ffire.cc/files/招标文件备案表(第二次).pdf"
90
+ file = "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"
91
+ "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 这个文件讲了什么?"
92
+ # file = "https://oss.ffire.cc/files/百炼系列手机产品介绍.docx"
93
+ # file = Path("/Users/betterme/PycharmProjects/AI/MeUtils/meutils/llm/completions/rag/百炼系列手机产品介绍.docx")
94
+
95
+ # file = "/Users/betterme/PycharmProjects/AI/MeUtils/meutils/io/img_1.png"
96
+
97
+ # openai.BadRequestError: Error code: 400 - {'error': {'message': 'text extract error: 没有解析出内容', 'type': 'invalid_request_error'}}
98
+ # file = "https://oss.ffire.cc/files/kling_watermark.png"
99
+
100
+ # with timer():
101
+ # r = arun(file_extract(file, moonshot_client))
102
+
103
+ # with timer():
104
+ # r = arun(file_extract(file, provider='kimi'))
105
+
106
+ with timer():
107
+ arun(file_extract(file))