MeUtils 2025.4.9.10.39.6__py3-none-any.whl → 2025.4.11.17.37.3__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.
- {MeUtils-2025.4.9.10.39.6.dist-info → MeUtils-2025.4.11.17.37.3.dist-info}/METADATA +266 -266
- {MeUtils-2025.4.9.10.39.6.dist-info → MeUtils-2025.4.11.17.37.3.dist-info}/RECORD +40 -37
- examples/_openaisdk/openai_google.py +38 -31
- meutils/apis/{google_apis → google}/audios.py +5 -2
- meutils/apis/google/chat.py +372 -0
- meutils/apis/google/files.py +29 -0
- meutils/apis/{google_apis → google}/google2openai.py +8 -4
- meutils/apis/google/images.py +27 -0
- meutils/apis/{google_apis → google}/search.py +7 -5
- meutils/apis/jimeng/images.py +41 -8
- meutils/apis/search/metaso.py +2 -2
- meutils/apis/siliconflow/images.py +5 -3
- meutils/caches/acache.py +1 -1
- meutils/common.py +1 -0
- meutils/data/VERSION +1 -1
- meutils/decorators/catch.py +0 -8
- meutils/decorators/common.py +86 -19
- meutils/decorators/contextmanagers.py +103 -14
- meutils/decorators/demo.py +76 -14
- meutils/io/files_utils.py +2 -3
- meutils/io/openai_files.py +11 -6
- meutils/llm/check_utils.py +20 -1
- meutils/llm/openai_polling/__init__.py +11 -0
- meutils/llm/openai_polling/chat.py +45 -0
- meutils/{apis/google_apis → llm/openai_polling}/images.py +4 -2
- meutils/llm/openai_utils/common.py +1 -1
- meutils/notice/feishu.py +5 -2
- meutils/schemas/image_types.py +26 -3
- meutils/schemas/oneapi/common.py +12 -0
- meutils/schemas/openai_types.py +10 -0
- meutils/serving/fastapi/dependencies/__init__.py +4 -1
- meutils/serving/fastapi/dependencies/auth.py +10 -6
- meutils/serving/fastapi/exceptions/http_error.py +2 -2
- meutils/str_utils/__init__.py +30 -2
- meutils/apis/google_apis/common.py +0 -243
- meutils/apis/google_apis/files.py +0 -19
- {MeUtils-2025.4.9.10.39.6.dist-info → MeUtils-2025.4.11.17.37.3.dist-info}/LICENSE +0 -0
- {MeUtils-2025.4.9.10.39.6.dist-info → MeUtils-2025.4.11.17.37.3.dist-info}/WHEEL +0 -0
- {MeUtils-2025.4.9.10.39.6.dist-info → MeUtils-2025.4.11.17.37.3.dist-info}/entry_points.txt +0 -0
- {MeUtils-2025.4.9.10.39.6.dist-info → MeUtils-2025.4.11.17.37.3.dist-info}/top_level.txt +0 -0
- /meutils/apis/{google_apis → google}/__init__.py +0 -0
- /meutils/apis/{google_apis → google}/gemini_sdk.py +0 -0
meutils/decorators/catch.py
CHANGED
@@ -8,7 +8,6 @@
|
|
8
8
|
# @Software : PyCharm
|
9
9
|
# @Description :
|
10
10
|
from meutils.pipe import *
|
11
|
-
from meutils.log_utils import logger4wecom
|
12
11
|
|
13
12
|
|
14
13
|
def wecom_hook(title='Task Done', text=None, hook_url=None):
|
@@ -30,12 +29,6 @@ def wecom_hook(title='Task Done', text=None, hook_url=None):
|
|
30
29
|
|
31
30
|
logger.info(f"{title} done in {mins} m")
|
32
31
|
|
33
|
-
logger4wecom(
|
34
|
-
title=title,
|
35
|
-
text=f"**{wrapped.__name__}:** {r if text is None else text}\n耗时 {mins} m",
|
36
|
-
hook_url=hook_url
|
37
|
-
)
|
38
|
-
|
39
32
|
return r
|
40
33
|
|
41
34
|
return wrapper
|
@@ -54,7 +47,6 @@ def wecom_catch(hook_url=None, more_info=True):
|
|
54
47
|
{info.strip()}
|
55
48
|
```
|
56
49
|
""".strip()
|
57
|
-
logger4wecom(wrapped.__name__, text, hook_url)
|
58
50
|
|
59
51
|
return wrapper
|
60
52
|
|
meutils/decorators/common.py
CHANGED
@@ -7,19 +7,20 @@
|
|
7
7
|
# @WeChat : 313303303
|
8
8
|
# @Software : PyCharm
|
9
9
|
# @Description :
|
10
|
-
import importlib
|
11
10
|
import os
|
12
11
|
import sys
|
13
12
|
import time
|
14
|
-
|
15
|
-
|
13
|
+
import wrapt
|
14
|
+
import asyncio
|
15
|
+
import inspect
|
16
16
|
import schedule
|
17
17
|
import threading
|
18
18
|
import traceback
|
19
|
-
import
|
19
|
+
import importlib
|
20
20
|
|
21
21
|
from loguru import logger
|
22
22
|
from tqdm.auto import tqdm
|
23
|
+
from functools import wraps
|
23
24
|
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
|
24
25
|
from contextlib import contextmanager, asynccontextmanager
|
25
26
|
from typing import *
|
@@ -148,14 +149,6 @@ def do_nothing(func, *args, **kwargs):
|
|
148
149
|
return func(*args, **kwargs)
|
149
150
|
|
150
151
|
|
151
|
-
@decorator
|
152
|
-
def try_catch(func, is_trace=False, *args, **kwargs):
|
153
|
-
try:
|
154
|
-
return func(*args, **kwargs)
|
155
|
-
except Exception as e:
|
156
|
-
return {'error': traceback.format_exc().strip() if is_trace else e}
|
157
|
-
|
158
|
-
|
159
152
|
@decorator
|
160
153
|
def timeout(func, seconds=1, *args, **kwargs):
|
161
154
|
future = ThreadPoolExecutor(1).submit(func, *args, **kwargs)
|
@@ -398,12 +391,64 @@ def limit(limit_value: str = '1/second', key_func: Callable[..., str] = None, er
|
|
398
391
|
return inner
|
399
392
|
|
400
393
|
|
394
|
+
def try_catch(
|
395
|
+
task: Optional[str] = None,
|
396
|
+
callback: Optional[Callable] = None,
|
397
|
+
is_trace: bool = False,
|
398
|
+
):
|
399
|
+
from meutils.notice.feishu import send_message_for_try_catch
|
400
|
+
|
401
|
+
callback = callback or send_message_for_try_catch # logger.error
|
402
|
+
|
403
|
+
def decorator(func):
|
404
|
+
@wraps(func)
|
405
|
+
def wrapper(*args, **kwargs):
|
406
|
+
task_name = task or f"{func.__module__}.{func.__name__}"
|
407
|
+
|
408
|
+
data = {
|
409
|
+
"task_name": task_name,
|
410
|
+
# "args": args,
|
411
|
+
# "kwargs": kwargs,
|
412
|
+
# "defined_args": inspect.getfullargspec(func).args, # .varargs
|
413
|
+
}
|
414
|
+
|
415
|
+
logger.debug(data)
|
416
|
+
|
417
|
+
async def async_wrapper():
|
418
|
+
try:
|
419
|
+
if asyncio.iscoroutinefunction(func):
|
420
|
+
return await func(*args, **kwargs)
|
421
|
+
else:
|
422
|
+
return func(*args, **kwargs)
|
423
|
+
except Exception as e:
|
424
|
+
|
425
|
+
if is_trace:
|
426
|
+
error_msg = f"{task_name}:\n{traceback.format_exc()}"
|
427
|
+
else:
|
428
|
+
error_msg = f"{task_name}: {e}"
|
429
|
+
|
430
|
+
data["error"] = error_msg
|
431
|
+
callback(data)
|
432
|
+
|
433
|
+
raise
|
434
|
+
|
435
|
+
if asyncio.iscoroutinefunction(func):
|
436
|
+
return async_wrapper()
|
437
|
+
else:
|
438
|
+
try:
|
439
|
+
return asyncio.get_event_loop().run_until_complete(async_wrapper())
|
440
|
+
except RuntimeError:
|
441
|
+
# 如果没有事件循环(例如在同步环境中),则直接运行
|
442
|
+
return async_wrapper()
|
443
|
+
|
444
|
+
return wrapper
|
445
|
+
|
446
|
+
return decorator
|
401
447
|
|
402
448
|
|
403
449
|
if __name__ == '__main__':
|
404
450
|
import time
|
405
451
|
|
406
|
-
|
407
452
|
# @timeout()
|
408
453
|
# def ff():
|
409
454
|
# import time
|
@@ -476,11 +521,33 @@ if __name__ == '__main__':
|
|
476
521
|
# while 1:
|
477
522
|
# pass
|
478
523
|
|
479
|
-
def f():
|
480
|
-
|
481
|
-
|
524
|
+
# def f():
|
525
|
+
# return 1 / 0
|
526
|
+
# # return 1
|
527
|
+
#
|
528
|
+
#
|
529
|
+
# with tryer('try'):
|
530
|
+
# a = f()
|
531
|
+
# print(a)
|
532
|
+
|
533
|
+
from meutils.pipe import *
|
534
|
+
from meutils.notice.feishu import send_message_for_try_catch
|
535
|
+
|
536
|
+
|
537
|
+
@try_catch(is_trace=False)
|
538
|
+
async def my_async_function(x=1, y=1):
|
539
|
+
# 您的异步函数代码
|
540
|
+
pass
|
541
|
+
1 / 0
|
482
542
|
|
483
543
|
|
484
|
-
|
485
|
-
|
486
|
-
|
544
|
+
async def main():
|
545
|
+
await my_async_function(x=111, y=10000)
|
546
|
+
|
547
|
+
|
548
|
+
# @async_try_catch(task="Custom Task Name", fallback=some_fallback_function)
|
549
|
+
# async def another_async_function():
|
550
|
+
# # 另一个异步函数的代码
|
551
|
+
# pass
|
552
|
+
|
553
|
+
arun(main())
|
@@ -9,6 +9,7 @@
|
|
9
9
|
# @Description :
|
10
10
|
|
11
11
|
from meutils.pipe import *
|
12
|
+
from meutils.notice.feishu import send_message_for_try_catch
|
12
13
|
|
13
14
|
from contextlib import contextmanager, asynccontextmanager
|
14
15
|
from concurrent.futures import ThreadPoolExecutor, as_completed, TimeoutError
|
@@ -53,12 +54,13 @@ async def atry_catcher(task="Task", fallback: Callable = None, is_trace: bool =
|
|
53
54
|
except Exception as e:
|
54
55
|
error = traceback.format_exc() if is_trace else e
|
55
56
|
logger.error(f"{task}: {error}")
|
57
|
+
|
56
58
|
if fallback:
|
57
59
|
yield await fallback()
|
58
60
|
|
59
61
|
|
60
62
|
@contextmanager
|
61
|
-
def timeout_task_executor(timeout: float=3, max_workers: int = None):
|
63
|
+
def timeout_task_executor(timeout: float = 3, max_workers: int = None):
|
62
64
|
"""
|
63
65
|
一个上下文管理器,用于执行任务并设置超时时间。
|
64
66
|
:param timeout: 超时时间(秒)。
|
@@ -85,6 +87,90 @@ def timeout_task_executor(timeout: float=3, max_workers: int = None):
|
|
85
87
|
executor.shutdown(wait=False) # 不等待未完成的任务,直接关闭
|
86
88
|
|
87
89
|
|
90
|
+
@asynccontextmanager
|
91
|
+
async def atry_catcher(task="Task", fallback: Callable = None, is_trace: bool = False):
|
92
|
+
try:
|
93
|
+
yield
|
94
|
+
except Exception as e:
|
95
|
+
error = traceback.format_exc() if is_trace else e
|
96
|
+
logger.error(f"{task}: {error}")
|
97
|
+
if fallback:
|
98
|
+
yield await fallback()
|
99
|
+
|
100
|
+
|
101
|
+
@asynccontextmanager
|
102
|
+
async def atry_catch(
|
103
|
+
task: Optional[str] = None,
|
104
|
+
callback: Optional[Callable] = None,
|
105
|
+
is_trace: bool = False,
|
106
|
+
**kwargs,
|
107
|
+
):
|
108
|
+
callback = callback or send_message_for_try_catch
|
109
|
+
|
110
|
+
task_name = task or "Unnamed TryCatch Task"
|
111
|
+
|
112
|
+
data = {
|
113
|
+
"task_name": task_name,
|
114
|
+
}
|
115
|
+
for k, v in kwargs.items():
|
116
|
+
if isinstance(v, BaseModel):
|
117
|
+
v = v.model_dump(exclude_none=True)
|
118
|
+
data[k] = v
|
119
|
+
|
120
|
+
# logger.debug(data)
|
121
|
+
|
122
|
+
try:
|
123
|
+
yield
|
124
|
+
except Exception as e:
|
125
|
+
if is_trace:
|
126
|
+
error_msg = f"""{traceback.format_exc()}"""
|
127
|
+
else:
|
128
|
+
error_msg = f"{e}"
|
129
|
+
|
130
|
+
data["error"] = error_msg
|
131
|
+
|
132
|
+
callback(data)
|
133
|
+
raise
|
134
|
+
|
135
|
+
|
136
|
+
@contextmanager
|
137
|
+
def try_catch(
|
138
|
+
task: Optional[str] = None,
|
139
|
+
callback: Optional[Callable] = None,
|
140
|
+
is_trace: bool = False,
|
141
|
+
**kwargs,
|
142
|
+
):
|
143
|
+
callback = callback or send_message_for_try_catch
|
144
|
+
|
145
|
+
task_name = task or "Unnamed TryCatch Task"
|
146
|
+
|
147
|
+
data = {
|
148
|
+
"task_name": task_name,
|
149
|
+
}
|
150
|
+
for k, v in kwargs.items():
|
151
|
+
if isinstance(v, BaseModel):
|
152
|
+
v = v.model_dump(exclude_none=True)
|
153
|
+
elif isinstance(v, typing.Mapping):
|
154
|
+
v = dict(v)
|
155
|
+
|
156
|
+
data[k] = v
|
157
|
+
|
158
|
+
logger.debug(data)
|
159
|
+
|
160
|
+
try:
|
161
|
+
yield
|
162
|
+
except Exception as e:
|
163
|
+
if is_trace:
|
164
|
+
error_msg = f"""{traceback.format_exc()}"""
|
165
|
+
else:
|
166
|
+
error_msg = f"{e}"
|
167
|
+
|
168
|
+
data["error"] = error_msg
|
169
|
+
|
170
|
+
callback(data)
|
171
|
+
raise e
|
172
|
+
|
173
|
+
|
88
174
|
if __name__ == '__main__':
|
89
175
|
# async def f():
|
90
176
|
# return 1/0
|
@@ -93,16 +179,19 @@ if __name__ == '__main__':
|
|
93
179
|
# with try_catcher("test"):
|
94
180
|
# arun(f())
|
95
181
|
|
96
|
-
def example_task():
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
with timeout_task_executor(timeout=3) as execute:
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
182
|
+
# def example_task():
|
183
|
+
# print("Starting task...")
|
184
|
+
# time.sleep(4) # 模拟耗时任务
|
185
|
+
# print("Task completed!")
|
186
|
+
# return "Done"
|
187
|
+
#
|
188
|
+
#
|
189
|
+
# with timeout_task_executor(timeout=3) as execute:
|
190
|
+
# try:
|
191
|
+
# result = execute(example_task)
|
192
|
+
# print(f"Task result: {result}")
|
193
|
+
# except TimeoutError:
|
194
|
+
# print("Task did not complete in time.")
|
195
|
+
|
196
|
+
with try_catch("test"):
|
197
|
+
1 / 0
|
meutils/decorators/demo.py
CHANGED
@@ -7,26 +7,88 @@
|
|
7
7
|
# @WeChat : 313303303
|
8
8
|
# @Software : PyCharm
|
9
9
|
# @Description :
|
10
|
+
import asyncio
|
11
|
+
import traceback
|
12
|
+
from typing import Optional, Callable
|
13
|
+
from contextlib import asynccontextmanager, contextmanager
|
10
14
|
|
15
|
+
from meutils.notice.feishu import send_message_for_try_catch
|
11
16
|
|
12
|
-
from meutils.decorators.feishu import *
|
13
17
|
|
14
|
-
|
15
|
-
|
18
|
+
@asynccontextmanager
|
19
|
+
async def atry_catch(
|
20
|
+
task: Optional[str] = None,
|
21
|
+
callback: Optional[Callable] = None,
|
22
|
+
is_trace: bool = False,
|
23
|
+
):
|
24
|
+
callback = callback or send_message_for_try_catch
|
25
|
+
|
26
|
+
task_name = task or "Unnamed TryCatch Task"
|
27
|
+
|
28
|
+
data = {
|
29
|
+
"task_name": task_name,
|
30
|
+
}
|
31
|
+
|
32
|
+
# logger.debug(data)
|
33
|
+
|
34
|
+
try:
|
35
|
+
yield
|
36
|
+
except Exception as e:
|
37
|
+
if is_trace:
|
38
|
+
error_msg = f"""{task_name}:\n{traceback.format_exc()}"""
|
39
|
+
else:
|
40
|
+
error_msg = f"{task_name}: {e}"
|
41
|
+
|
42
|
+
data["error"] = error_msg
|
43
|
+
|
44
|
+
callback(data)
|
45
|
+
raise
|
46
|
+
|
16
47
|
|
17
|
-
|
48
|
+
@contextmanager
|
49
|
+
def try_catch(
|
50
|
+
task: Optional[str] = None,
|
51
|
+
callback: Optional[Callable] = None,
|
52
|
+
is_trace: bool = False,
|
53
|
+
):
|
54
|
+
callback = callback or send_message_for_try_catch
|
18
55
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
56
|
+
task_name = task or "Unnamed TryCatch Task"
|
57
|
+
|
58
|
+
data = {
|
59
|
+
"task_name": task_name,
|
60
|
+
}
|
61
|
+
|
62
|
+
# logger.debug(data)
|
25
63
|
|
26
|
-
async def main():
|
27
64
|
try:
|
28
|
-
|
65
|
+
yield
|
29
66
|
except Exception as e:
|
30
|
-
|
67
|
+
if is_trace:
|
68
|
+
error_msg = f"""{task_name}:\n{traceback.format_exc()}"""
|
69
|
+
else:
|
70
|
+
error_msg = f"{task_name}: {e}"
|
71
|
+
|
72
|
+
data["error"] = error_msg
|
73
|
+
|
74
|
+
callback(data)
|
75
|
+
raise
|
76
|
+
|
77
|
+
|
78
|
+
if __name__ == '__main__':
|
79
|
+
from meutils.pipe import *
|
80
|
+
|
81
|
+
|
82
|
+
async def f():
|
83
|
+
return 1
|
84
|
+
|
85
|
+
|
86
|
+
async def main():
|
87
|
+
# with atry_catch_context(task="test", is_trace=True):
|
88
|
+
# 1 / 0
|
89
|
+
with try_catch(task="test", is_trace=True):
|
90
|
+
logger.debug(await f())
|
91
|
+
1 / 0
|
92
|
+
|
31
93
|
|
32
|
-
asyncio.run(main())
|
94
|
+
asyncio.run(main())
|
meutils/io/files_utils.py
CHANGED
@@ -50,7 +50,6 @@ def base64_to_bytes(base64_image_string):
|
|
50
50
|
|
51
51
|
|
52
52
|
@retrying()
|
53
|
-
@rcache(ttl=300, serializer='pickle') # todo: UploadFile不一定兼容
|
54
53
|
async def to_bytes(
|
55
54
|
file: Union[UploadFile, str, bytes],
|
56
55
|
headers: Optional[dict] = None
|
@@ -79,12 +78,12 @@ async def to_bytes(
|
|
79
78
|
resp = await cilent.get(file)
|
80
79
|
file_bytes = resp.content
|
81
80
|
|
82
|
-
elif isinstance(file, str) and len(file) >
|
81
|
+
elif isinstance(file, str) and len(file) > 1024: # base64
|
83
82
|
logger.debug(f"FileType: BASE64")
|
84
83
|
|
85
84
|
file_bytes = base64_to_bytes(file)
|
86
85
|
|
87
|
-
elif isinstance(file, str) and len(file) <
|
86
|
+
elif isinstance(file, str) and len(file) < 1024 and Path(file).is_file(): # file
|
88
87
|
logger.debug(f"FileType: PATH")
|
89
88
|
|
90
89
|
file_bytes = Path(file).read_bytes()
|
meutils/io/openai_files.py
CHANGED
@@ -50,13 +50,15 @@ async def delete_files(client, threshold: int = 666):
|
|
50
50
|
|
51
51
|
|
52
52
|
@rcache(ttl=7 * 24 * 3600)
|
53
|
-
async def
|
53
|
+
async def file_extract(file):
|
54
54
|
"""
|
55
55
|
|
56
56
|
:param file: url bytes path
|
57
57
|
:return:
|
58
58
|
"""
|
59
59
|
# url
|
60
|
+
if isinstance(file, list):
|
61
|
+
return await asyncio.gather(*map(file_extract, file))
|
60
62
|
|
61
63
|
filename = Path(file).name if isinstance(file, str) else 'untitled'
|
62
64
|
mime_type = guess_mime_type(file)
|
@@ -108,12 +110,14 @@ async def _file_extract(file):
|
|
108
110
|
return data
|
109
111
|
|
110
112
|
|
111
|
-
|
112
|
-
if isinstance(files, str):
|
113
|
-
return await _file_extract(files)
|
113
|
+
# http://admin.ilovechatgpt.top/file/boshihouyanjiurenyuankaitipingshenbiaochugaofanyidocx_88256801.docx
|
114
114
|
|
115
|
-
|
116
|
-
|
115
|
+
# async def file_extract(files):
|
116
|
+
# if isinstance(files, str):
|
117
|
+
# return await _file_extract(files)
|
118
|
+
#
|
119
|
+
# tasks = [_file_extract(file) for file in files]
|
120
|
+
# return await asyncio.gather(*tasks)
|
117
121
|
|
118
122
|
|
119
123
|
# FileObject(id='1741136989_8dd96cbee6274251b7e4c9568779bd6a', bytes=82947, created_at=1741136989, filename='kling_watermark.png', object='file', status=None, status_details=None)
|
@@ -153,6 +157,7 @@ if __name__ == '__main__':
|
|
153
157
|
file = "http://admin.ilovechatgpt.top/file/yuzhicaizaibutongnianlingquntixiaofeixingweijishichangdiaochawenjuanweishanjianbanpptx_59787479.pptx"
|
154
158
|
file = "https://oss.ffire.cc/files/百炼系列手机产品介绍.docx"
|
155
159
|
# file = "https://app.yinxiang.com/fx/8b8bba1e-b254-40ff-81e1-fa3427429efe"
|
160
|
+
file = "http://admin.ilovechatgpt.top/file/boshihouyanjiurenyuankaitipingshenbiaochugaofanyidocx_88256801.docx"
|
156
161
|
|
157
162
|
print(guess_mime_type(file))
|
158
163
|
|
meutils/llm/check_utils.py
CHANGED
@@ -130,6 +130,25 @@ async def check_token_for_moonshot(api_key, threshold: float = 0):
|
|
130
130
|
return False
|
131
131
|
|
132
132
|
|
133
|
+
@retrying()
|
134
|
+
async def check_token_for_gemini(api_key):
|
135
|
+
if not isinstance(api_key, str):
|
136
|
+
return await check_tokens(api_key, check_token_for_gemini)
|
137
|
+
try:
|
138
|
+
client = AsyncOpenAI(
|
139
|
+
api_key=api_key,
|
140
|
+
base_url=os.getenv("GOOGLE_BASE_URL"),
|
141
|
+
)
|
142
|
+
await client.models.list()
|
143
|
+
return True
|
144
|
+
except TimeoutException as e:
|
145
|
+
raise
|
146
|
+
|
147
|
+
except Exception as e:
|
148
|
+
logger.error(f"Error: {e}\n{api_key}")
|
149
|
+
return False
|
150
|
+
|
151
|
+
|
133
152
|
if __name__ == '__main__':
|
134
153
|
from meutils.config_utils.lark_utils import get_next_token_for_polling
|
135
154
|
|
@@ -149,4 +168,4 @@ if __name__ == '__main__':
|
|
149
168
|
arun(check_token_for_siliconflow("sk-vpeietyomqjvizlzfuztzthggcqvutowgbmhjggsmwuhsomg"))
|
150
169
|
"https://xchatllm.feishu.cn/sheets/Bmjtst2f6hfMqFttbhLcdfRJnNf?sheet=79272d"
|
151
170
|
|
152
|
-
# arun(check_token_for_moonshot("sk-Qnr87vtf2Q6MEfc2mVNkVZ4qaoZg3smH9527I25QgcFe7HrT"))
|
171
|
+
# arun(check_token_for_moonshot("sk-Qnr87vtf2Q6MEfc2mVNkVZ4qaoZg3smH9527I25QgcFe7HrT"))
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# @Project : AI. @by PyCharm
|
4
|
+
# @File : chat
|
5
|
+
# @Time : 2025/4/10 16:06
|
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
|
+
from meutils.llm.openai_utils import to_openai_params
|
14
|
+
|
15
|
+
from meutils.schemas.openai_types import CompletionRequest
|
16
|
+
|
17
|
+
|
18
|
+
class Completions(object):
|
19
|
+
|
20
|
+
def __init__(self, base_url: Optional[str] = None, api_key: Optional[str] = None):
|
21
|
+
self.client = AsyncOpenAI(base_url=base_url, api_key=api_key)
|
22
|
+
|
23
|
+
async def create(self, request: CompletionRequest):
|
24
|
+
data = to_openai_params(request)
|
25
|
+
if 'gemini' in request.model:
|
26
|
+
data.pop("seed", None)
|
27
|
+
data.pop("presence_penalty", None)
|
28
|
+
data.pop("frequency_penalty", None)
|
29
|
+
data.pop("extra_body", None)
|
30
|
+
|
31
|
+
return await self.client.chat.completions.create(**data)
|
32
|
+
|
33
|
+
|
34
|
+
if __name__ == '__main__':
|
35
|
+
# 测试
|
36
|
+
|
37
|
+
request = CompletionRequest(
|
38
|
+
model="gpt-4o-mini",
|
39
|
+
messages=[
|
40
|
+
{"role": "system", "content": "你是一个助手"},
|
41
|
+
{"role": "user", "content": "你好"}
|
42
|
+
],
|
43
|
+
stream=False
|
44
|
+
)
|
45
|
+
arun(Completions().create(request))
|
@@ -2,10 +2,12 @@
|
|
2
2
|
# -*- coding: utf-8 -*-
|
3
3
|
# @Project : AI. @by PyCharm
|
4
4
|
# @File : images
|
5
|
-
# @Time : 2025/4/
|
5
|
+
# @Time : 2025/4/10 16:07
|
6
6
|
# @Author : betterme
|
7
7
|
# @WeChat : meutils
|
8
8
|
# @Software : PyCharm
|
9
|
-
# @Description :
|
9
|
+
# @Description :
|
10
10
|
|
11
11
|
from meutils.pipe import *
|
12
|
+
|
13
|
+
|
@@ -193,7 +193,7 @@ async def create_chat_completion_chunk(
|
|
193
193
|
Iterator[Union[str, ChatCompletionChunk]],
|
194
194
|
AsyncIterator[Union[str, ChatCompletionChunk]]
|
195
195
|
],
|
196
|
-
redirect_model: str = ' ',
|
196
|
+
redirect_model: str = ' ', # todo: response_model
|
197
197
|
chat_id: Optional[str] = None
|
198
198
|
):
|
199
199
|
""" todo: 替换 前缀
|
meutils/notice/feishu.py
CHANGED
@@ -108,8 +108,11 @@ def catch(
|
|
108
108
|
send_message_for_images = partial(send_message, url=IMAGES)
|
109
109
|
send_message_for_kling = partial(send_message, url=KLING)
|
110
110
|
|
111
|
-
|
112
|
-
|
111
|
+
http_feishu_url = "https://open.feishu.cn/open-apis/bot/v2/hook/d1c7b67d-b0f8-4067-a2f5-109f20eeb696"
|
112
|
+
send_message_for_http = partial(send_message, url=http_feishu_url)
|
113
|
+
|
114
|
+
try_catch_feishu_url = "https://open.feishu.cn/open-apis/bot/v2/hook/887fe4d3-8bcd-4cfb-bac9-62f776091ca2"
|
115
|
+
send_message_for_try_catch = partial(send_message, url=try_catch_feishu_url)
|
113
116
|
|
114
117
|
if __name__ == '__main__':
|
115
118
|
# send_message("xxx", title=None)
|
meutils/schemas/image_types.py
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
# @Description : todo: 通用比例适配
|
10
10
|
|
11
11
|
from meutils.pipe import *
|
12
|
+
from meutils.str_utils.regular_expression import parse_url
|
12
13
|
|
13
14
|
from pydantic import constr
|
14
15
|
from openai.types import ImagesResponse as _ImagesResponse, Image
|
@@ -43,7 +44,7 @@ ASPECT_RATIOS = {
|
|
43
44
|
class ImagesResponse(_ImagesResponse):
|
44
45
|
created: int = Field(default_factory=lambda: int(time.time()))
|
45
46
|
|
46
|
-
data: Optional[List[Union[Image, dict]]] =
|
47
|
+
data: Optional[List[Union[Image, dict]]] = []
|
47
48
|
|
48
49
|
image: Optional[Union[str, List[str]]] = None
|
49
50
|
|
@@ -99,6 +100,20 @@ class ImageRequest(BaseModel): # openai
|
|
99
100
|
if self.size:
|
100
101
|
self.size = self.size if 'x' in self.size else '512x512'
|
101
102
|
|
103
|
+
@cached_property
|
104
|
+
def image_and_prompt(self): # image prompt 目前是单图
|
105
|
+
if self.prompt.startswith('http') and (prompts := self.prompt.split(maxsplit=1)):
|
106
|
+
if len(prompts) == 2:
|
107
|
+
return prompts
|
108
|
+
else:
|
109
|
+
return prompts + [' ']
|
110
|
+
|
111
|
+
elif "http" in self.prompt and (images := parse_url(self.prompt)):
|
112
|
+
return images[0], self.prompt.replace(images[0], "")
|
113
|
+
|
114
|
+
else:
|
115
|
+
return None, self.prompt
|
116
|
+
|
102
117
|
class Config:
|
103
118
|
extra = "allow"
|
104
119
|
|
@@ -502,5 +517,13 @@ if __name__ == '__main__':
|
|
502
517
|
|
503
518
|
# print(ImagesResponse(data=[{'url': 1}]))
|
504
519
|
|
505
|
-
print(RecraftImageRequest(prompt="").model_dump_json())
|
506
|
-
print(RecraftImageRequest(prompt=""))
|
520
|
+
# print(RecraftImageRequest(prompt="").model_dump_json())
|
521
|
+
# print(RecraftImageRequest(prompt=""))
|
522
|
+
|
523
|
+
prompt = "https://oss.ffire.cc/files/kling_watermark.png 带个眼镜"
|
524
|
+
# prompt = "带个眼镜 https://oss.ffire.cc/files/kling_watermark.png"
|
525
|
+
prompt = "https://oss.ffire.cc/files/kling_watermark.png"
|
526
|
+
prompt = "画条狗"
|
527
|
+
|
528
|
+
request = ImageRequest(prompt=prompt)
|
529
|
+
print(request.image_and_prompt)
|