MeUtils 2025.6.6.18.15.9__py3-none-any.whl → 2025.6.9.9.17.14__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.6.6.18.15.9.dist-info → MeUtils-2025.6.9.9.17.14.dist-info}/METADATA +262 -262
- {MeUtils-2025.6.6.18.15.9.dist-info → MeUtils-2025.6.9.9.17.14.dist-info}/RECORD +25 -16
- meutils/apis/fal/images.py +11 -4
- meutils/apis/hailuoai/videos.py +3 -2
- meutils/apis/jimeng/common.py +1 -1
- meutils/apis/jimeng/images.py +0 -1
- meutils/apis/jimeng_global/__init__.py +10 -0
- meutils/apis/jimeng_global/audio.py +192 -0
- meutils/apis/jimeng_global/common.py +218 -0
- meutils/apis/jimeng_global/doubao_images.py +70 -0
- meutils/apis/jimeng_global/doubao_utils.py +175 -0
- meutils/apis/jimeng_global/files.py +368 -0
- meutils/apis/jimeng_global/images.py +744 -0
- meutils/apis/jimeng_global/videos.py +187 -0
- meutils/apis/jimeng_global/videos_videos.py +334 -0
- meutils/data/VERSION +1 -1
- meutils/schemas/image_types.py +6 -1
- meutils/schemas/jimeng_types.py +1 -0
- meutils/schemas/oneapi/common.py +4 -2
- meutils/str_utils/__init__.py +43 -6
- meutils/str_utils/regular_expression.py +1 -0
- {MeUtils-2025.6.6.18.15.9.dist-info → MeUtils-2025.6.9.9.17.14.dist-info}/LICENSE +0 -0
- {MeUtils-2025.6.6.18.15.9.dist-info → MeUtils-2025.6.9.9.17.14.dist-info}/WHEEL +0 -0
- {MeUtils-2025.6.6.18.15.9.dist-info → MeUtils-2025.6.9.9.17.14.dist-info}/entry_points.txt +0 -0
- {MeUtils-2025.6.6.18.15.9.dist-info → MeUtils-2025.6.9.9.17.14.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,187 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# @Project : AI. @by PyCharm
|
4
|
+
# @File : lip_sync
|
5
|
+
# @Time : 2025/1/3 16:17
|
6
|
+
# @Author : betterme
|
7
|
+
# @WeChat : meutils
|
8
|
+
# @Software : PyCharm
|
9
|
+
# @Description :
|
10
|
+
"""
|
11
|
+
1. 上传图片 image_to_avatar检测
|
12
|
+
2. 上传视频 video_to_avatar检测
|
13
|
+
3. 上传音频+创建任务
|
14
|
+
|
15
|
+
"""
|
16
|
+
import asyncio
|
17
|
+
|
18
|
+
from meutils.pipe import *
|
19
|
+
from meutils.str_utils.json_utils import json_path
|
20
|
+
|
21
|
+
from meutils.schemas.jimeng_types import BASE_URL
|
22
|
+
from meutils.schemas.video_types import VideoRequest
|
23
|
+
from meutils.schemas.task_types import TaskResponse
|
24
|
+
from meutils.apis.jimeng.common import get_headers, check_token
|
25
|
+
from meutils.apis.jimeng.files import upload_for_image, upload_for_video
|
26
|
+
|
27
|
+
from meutils.config_utils.lark_utils import get_next_token_for_polling
|
28
|
+
|
29
|
+
from fake_useragent import UserAgent
|
30
|
+
|
31
|
+
ua = UserAgent()
|
32
|
+
|
33
|
+
FEISHU_URL = "https://xchatllm.feishu.cn/sheets/GYCHsvI4qhnDPNtI4VPcdw2knEd?sheet=gAUw8s" # 视频
|
34
|
+
|
35
|
+
|
36
|
+
async def get_task(task_id: str, token: str = "916fed81175f5186a2c05375699ea40d"):
|
37
|
+
"""
|
38
|
+
$..image_to_avatar 成功: 先检测图片or视频
|
39
|
+
:param task_ids:
|
40
|
+
:return:
|
41
|
+
|
42
|
+
todo: fail_code
|
43
|
+
"""
|
44
|
+
task_ids = task_id.split()
|
45
|
+
|
46
|
+
url = "/mweb/v1/mget_generate_task"
|
47
|
+
headers = get_headers(url, token)
|
48
|
+
|
49
|
+
payload = {"task_id_list": task_ids}
|
50
|
+
async with httpx.AsyncClient(base_url=BASE_URL, headers=headers, timeout=60) as client:
|
51
|
+
response = await client.post(url, json=payload)
|
52
|
+
response.raise_for_status()
|
53
|
+
data = response.json()
|
54
|
+
logger.debug(bjson(data))
|
55
|
+
|
56
|
+
if video_urls := json_path(data, "$..video_url"): # 角色检测 create_realman_avatar
|
57
|
+
|
58
|
+
task_data = dict(zip(["video"] * len(video_urls), video_urls))
|
59
|
+
response = TaskResponse(task_id=task_id, data=task_data, metadata=data, status="success")
|
60
|
+
return response
|
61
|
+
|
62
|
+
else:
|
63
|
+
response = TaskResponse(task_id=task_id, metadata=data)
|
64
|
+
if (
|
65
|
+
(fail_codes := json_path(data, "$..fail_code"))
|
66
|
+
and fail_codes[-1] != "0"
|
67
|
+
and (messages := json_path(data, "$..fail_msg"))
|
68
|
+
):
|
69
|
+
response.message = f"{str(messages).lower().replace('success', '')}:{fail_codes}"
|
70
|
+
response.status = "fail"
|
71
|
+
return response
|
72
|
+
|
73
|
+
if will_cost := json_path(data, "$..will_cost"):
|
74
|
+
response.will_cost = will_cost[0]
|
75
|
+
|
76
|
+
if video_urls := json_path(data, "$..[360p,480p,720p].video_url"):
|
77
|
+
response.data = [{"video": _} for _ in video_urls]
|
78
|
+
response.status = "success"
|
79
|
+
|
80
|
+
response.fail_code = fail_codes and fail_codes[-1]
|
81
|
+
return response
|
82
|
+
|
83
|
+
|
84
|
+
async def create_task(request: VideoRequest, token: Optional[str] = None):
|
85
|
+
# token = "d2d142fc877e696484cc2fc521127b36" ################### 线上注释掉
|
86
|
+
|
87
|
+
token = token or await get_next_token_for_polling(FEISHU_URL, check_token)
|
88
|
+
|
89
|
+
url = "/mweb/v1/generate_video"
|
90
|
+
|
91
|
+
headers = get_headers(url, token)
|
92
|
+
|
93
|
+
task_extra = {
|
94
|
+
"promptSource": "custom",
|
95
|
+
"originSubmitId": str(uuid.uuid4()),
|
96
|
+
"isDefaultSeed": 1,
|
97
|
+
"originTemplateId": "",
|
98
|
+
"imageNameMapping": {},
|
99
|
+
"isUseAiGenPrompt": False,
|
100
|
+
"batchNumber": 1
|
101
|
+
}
|
102
|
+
payload = {
|
103
|
+
"submit_id": str(uuid.uuid4()),
|
104
|
+
"task_extra": json.dumps(task_extra),
|
105
|
+
"input": {
|
106
|
+
"video_aspect_ratio": request.aspect_ratio,
|
107
|
+
"seed": 1751603315, ##### seed 10位
|
108
|
+
"video_gen_inputs": [
|
109
|
+
{
|
110
|
+
"prompt": request.prompt,
|
111
|
+
"fps": 24,
|
112
|
+
"duration_ms": request.duration * 1000,
|
113
|
+
"video_mode": 2,
|
114
|
+
"template_id": ""
|
115
|
+
}
|
116
|
+
],
|
117
|
+
"priority": 0,
|
118
|
+
"model_req_key": "dreamina_ic_generate_video_model_vgfm_3.0", # request.model
|
119
|
+
},
|
120
|
+
"mode": "workbench",
|
121
|
+
"history_option": {},
|
122
|
+
"commerce_info": {
|
123
|
+
"resource_id": "generate_video",
|
124
|
+
"resource_id_type": "str",
|
125
|
+
"resource_sub_type": "aigc",
|
126
|
+
"benefit_type": "basic_video_operation_vgfm_v_three"
|
127
|
+
},
|
128
|
+
"client_trace_data": {}
|
129
|
+
}
|
130
|
+
|
131
|
+
if request.image_url:
|
132
|
+
# image_url = "tos-cn-i-tb4s082cfz/a116c6a9dcbc41b889f9aabdef645456"
|
133
|
+
image_url = await upload_for_image(request.image_url, token, biz="video")
|
134
|
+
# vid, uri = await upload_for_video(request.image_url, token)
|
135
|
+
# logger.debug(f"vid: {vid}, uri: {uri}")
|
136
|
+
payload['input'].pop('video_aspect_ratio', None)
|
137
|
+
payload['input']['video_gen_inputs'][0]['first_frame_image'] = {
|
138
|
+
"width": 1024,
|
139
|
+
"height": 1024,
|
140
|
+
"image_uri": image_url
|
141
|
+
}
|
142
|
+
|
143
|
+
logger.debug(bjson(payload))
|
144
|
+
|
145
|
+
async with httpx.AsyncClient(base_url=BASE_URL, headers=headers, timeout=60) as client:
|
146
|
+
response = await client.post(url, json=payload)
|
147
|
+
response.raise_for_status()
|
148
|
+
data = response.json()
|
149
|
+
logger.debug(bjson(data))
|
150
|
+
|
151
|
+
if task_ids := json_path(data, "$..task.task_id"):
|
152
|
+
task_id = task_ids[0]
|
153
|
+
return TaskResponse(task_id=task_id, system_fingerprint=token)
|
154
|
+
|
155
|
+
else:
|
156
|
+
"""
|
157
|
+
{
|
158
|
+
"ret": "1018",
|
159
|
+
"errmsg": "account punish limit ai generate",
|
160
|
+
"systime": "1749027488",
|
161
|
+
"logid": "202506041658081AB86654C66682A7DE2E",
|
162
|
+
"data": null
|
163
|
+
}
|
164
|
+
"""
|
165
|
+
|
166
|
+
raise Exception(data)
|
167
|
+
|
168
|
+
|
169
|
+
if __name__ == '__main__':
|
170
|
+
token = None
|
171
|
+
token = "d2d142fc877e696484cc2fc521127b36"
|
172
|
+
|
173
|
+
request = VideoRequest(
|
174
|
+
model="dreamina_ic_generate_video_model_vgfm_3.0",
|
175
|
+
prompt="笑起来",
|
176
|
+
image_url="https://oss.ffire.cc/files/kling_watermark.png", # 图生有问题
|
177
|
+
)
|
178
|
+
|
179
|
+
with timer():
|
180
|
+
r = arun(create_task(request, token))
|
181
|
+
print(r)
|
182
|
+
|
183
|
+
# arun(get_task(r.task_id))
|
184
|
+
# arun(get_task(r.task_id, "d2d142fc877e696484cc2fc521127b36"))
|
185
|
+
# task_id = "4620067333122"
|
186
|
+
#
|
187
|
+
# arun(get_task(task_id, token))
|
@@ -0,0 +1,334 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# @Project : AI. @by PyCharm
|
4
|
+
# @File : lip_sync
|
5
|
+
# @Time : 2025/1/3 16:17
|
6
|
+
# @Author : betterme
|
7
|
+
# @WeChat : meutils
|
8
|
+
# @Software : PyCharm
|
9
|
+
# @Description :
|
10
|
+
"""
|
11
|
+
1. 上传图片 image_to_avatar检测
|
12
|
+
2. 上传视频 video_to_avatar检测
|
13
|
+
3. 上传音频+创建任务
|
14
|
+
|
15
|
+
"""
|
16
|
+
import asyncio
|
17
|
+
|
18
|
+
from meutils.pipe import *
|
19
|
+
from meutils.str_utils.json_utils import json_path
|
20
|
+
|
21
|
+
from meutils.schemas.jimeng_types import BASE_URL, MODELS_MAP, FEISHU_URL
|
22
|
+
from meutils.schemas.video_types import LipsyncVideoRequest
|
23
|
+
from meutils.schemas.task_types import TaskResponse
|
24
|
+
from meutils.apis.jimeng.common import get_headers, check_token
|
25
|
+
from meutils.apis.jimeng.files import upload_for_image, upload_for_video
|
26
|
+
|
27
|
+
from meutils.config_utils.lark_utils import get_next_token_for_polling
|
28
|
+
|
29
|
+
from fake_useragent import UserAgent
|
30
|
+
|
31
|
+
ua = UserAgent()
|
32
|
+
|
33
|
+
|
34
|
+
async def create_realman_avatar(image_url: str, token: str):
|
35
|
+
if image_url.startswith("http"):
|
36
|
+
image_url = await upload_for_image(image_url, token)
|
37
|
+
|
38
|
+
url = "/mweb/v1/create_realman_avatar"
|
39
|
+
headers = get_headers(url, token)
|
40
|
+
|
41
|
+
payload = {
|
42
|
+
"input_list": [
|
43
|
+
{
|
44
|
+
"image_uri": image_url,
|
45
|
+
"submit_id": str(uuid.uuid4()),
|
46
|
+
"mode": 0
|
47
|
+
},
|
48
|
+
{
|
49
|
+
"image_uri": image_url,
|
50
|
+
"submit_id": str(uuid.uuid4()),
|
51
|
+
"mode": 1
|
52
|
+
}
|
53
|
+
]
|
54
|
+
}
|
55
|
+
|
56
|
+
async with httpx.AsyncClient(base_url=BASE_URL, headers=headers, timeout=60) as client:
|
57
|
+
response = await client.post(url, json=payload)
|
58
|
+
response.raise_for_status()
|
59
|
+
data = response.json()
|
60
|
+
logger.debug(bjson(data)) # 1914628189186
|
61
|
+
|
62
|
+
response = TaskResponse(metadata=data, system_fingerprint=token)
|
63
|
+
if task_ids := json_path(data, "$..task_id"): # 返回 imageurl vid
|
64
|
+
response.task_id = ' '.join(task_ids)
|
65
|
+
return response
|
66
|
+
|
67
|
+
else:
|
68
|
+
response.message = str(json_path(data, "$..message"))
|
69
|
+
response.status = "fail"
|
70
|
+
return response
|
71
|
+
|
72
|
+
|
73
|
+
async def get_task(task_id: str, token: str = "916fed81175f5186a2c05375699ea40d"):
|
74
|
+
"""
|
75
|
+
$..image_to_avatar 成功: 先检测图片or视频
|
76
|
+
:param task_ids:
|
77
|
+
:return:
|
78
|
+
"""
|
79
|
+
task_ids = task_id.split()
|
80
|
+
|
81
|
+
url = "/mweb/v1/mget_generate_task"
|
82
|
+
headers = get_headers(url, token)
|
83
|
+
|
84
|
+
payload = {"task_id_list": task_ids}
|
85
|
+
async with httpx.AsyncClient(base_url=BASE_URL, headers=headers, timeout=60) as client:
|
86
|
+
response = await client.post(url, json=payload)
|
87
|
+
response.raise_for_status()
|
88
|
+
data = response.json()
|
89
|
+
logger.debug(bjson(data))
|
90
|
+
|
91
|
+
if json_path(data, "$..image_to_avatar"): # 角色检测 create_realman_avatar
|
92
|
+
resource_id_std = resource_id_loopy = ""
|
93
|
+
if resource_id_stds := json_path(data, "$..resource_id_std"):
|
94
|
+
resource_id_std = "".join(resource_id_stds)
|
95
|
+
|
96
|
+
if resource_id_loopys := json_path(data, "$..resource_id_loopy"):
|
97
|
+
resource_id_loopy = "".join(resource_id_loopys)
|
98
|
+
|
99
|
+
task_data = {
|
100
|
+
"resource_id_std": resource_id_std,
|
101
|
+
"resource_id_loopy": resource_id_loopy
|
102
|
+
}
|
103
|
+
response = TaskResponse(task_id=task_id, data=task_data, metadata=data)
|
104
|
+
if resource_id_std and resource_id_loopy:
|
105
|
+
response.status = "success"
|
106
|
+
|
107
|
+
if (message := json_path(data, "$..image_to_avatar.message")) and "fail" in str(message).lower():
|
108
|
+
response.message = str(message)
|
109
|
+
response.status = "fail"
|
110
|
+
|
111
|
+
return response
|
112
|
+
|
113
|
+
else:
|
114
|
+
response = TaskResponse(task_id=task_id, metadata=data)
|
115
|
+
if (message := json_path(data, "$..fail_msg")) and "success" not in str(message).lower():
|
116
|
+
response.message = str(message)
|
117
|
+
response.status = "fail"
|
118
|
+
return response
|
119
|
+
|
120
|
+
if will_cost := json_path(data, "$..will_cost"):
|
121
|
+
response.will_cost = will_cost[0]
|
122
|
+
|
123
|
+
if video_urls := json_path(data, "$..[360p,480p,720p].video_url"):
|
124
|
+
response.data = [{"video": _} for _ in video_urls]
|
125
|
+
|
126
|
+
return response
|
127
|
+
|
128
|
+
|
129
|
+
async def create_task(request: LipsyncVideoRequest, token: Optional[str] = None):
|
130
|
+
# token = token or await get_next_token_for_polling(FEISHU_URL, check_token)
|
131
|
+
token = "7c5e148d9fa858e3180c42f843c20454" # 年付
|
132
|
+
token = "916fed81175f5186a2c05375699ea40d" # 月付
|
133
|
+
|
134
|
+
url = "/mweb/v1/batch_generate_video"
|
135
|
+
|
136
|
+
headers = get_headers(url, token)
|
137
|
+
|
138
|
+
model = request.model
|
139
|
+
scene = "lip_sync_image"
|
140
|
+
image_url = await upload_for_image(request.image_url, token)
|
141
|
+
|
142
|
+
# 角色检测
|
143
|
+
realman_avatar_response = await create_realman_avatar(image_url, token)
|
144
|
+
if realman_avatar_response.status == "fail":
|
145
|
+
return realman_avatar_response
|
146
|
+
|
147
|
+
else:
|
148
|
+
for _ in range(10):
|
149
|
+
task_response = await get_task(realman_avatar_response.task_id, token)
|
150
|
+
if task_response.status == "fail":
|
151
|
+
logger.debug("fail")
|
152
|
+
return task_response
|
153
|
+
elif task_response.status == "success":
|
154
|
+
logger.debug("success")
|
155
|
+
|
156
|
+
realman_avatar_response = task_response
|
157
|
+
break
|
158
|
+
else:
|
159
|
+
await asyncio.sleep(3)
|
160
|
+
continue
|
161
|
+
|
162
|
+
audio_vid, audio_url = await upload_for_video(request.audio_url, token)
|
163
|
+
|
164
|
+
resource_id_std = realman_avatar_response.data.get("resource_id_std")
|
165
|
+
resource_id_loopy = realman_avatar_response.data.get("resource_id_loopy")
|
166
|
+
|
167
|
+
i2v_opt = v2v_opt = {}
|
168
|
+
if request.video_url:
|
169
|
+
v2v_opt = {}
|
170
|
+
|
171
|
+
# payload = {
|
172
|
+
# "submit_id": "",
|
173
|
+
# "task_extra": "{\"promptSource\":\"photo_lip_sync\",\"generateTimes\":1,\"lipSyncInfo\":{\"sourceType\":\"local-file\",\"name\":\"vyFWygmZsIZlUO4s0nr2n.wav\"},\"isUseAiGenPrompt\":false,\"batchNumber\":1}",
|
174
|
+
# "http_common_info": {
|
175
|
+
# "aid": 513695
|
176
|
+
# },
|
177
|
+
# "input": {
|
178
|
+
# "seed": 3112889115,
|
179
|
+
# "video_gen_inputs": [
|
180
|
+
# {
|
181
|
+
# "v2v_opt": {},
|
182
|
+
# "i2v_opt": {
|
183
|
+
# "realman_avatar": {
|
184
|
+
# "enable": True,
|
185
|
+
# "origin_image": {
|
186
|
+
# # "width": 800,
|
187
|
+
# # "height": 1200,
|
188
|
+
# "image_uri": "tos-cn-i-tb4s082cfz/4dead1bfc8e84572a91f2e047016a351",
|
189
|
+
# "image_url": ""
|
190
|
+
# },
|
191
|
+
# "origin_audio": {
|
192
|
+
# # "duration": 9.976625,
|
193
|
+
# "vid": "v02870g10004cu8d4r7og65j2vr5opb0"
|
194
|
+
# },
|
195
|
+
#
|
196
|
+
# "resource_id_std": "381c534f-bcef-482e-8f17-5b30b64e41a1",
|
197
|
+
# "resource_id_loopy": "b9ac51cb-e26c-4b63-81d9-34ed24053032",
|
198
|
+
# #
|
199
|
+
# # "tts_info": "{\"name\":\"vyFWygmZsIZlUO4s0nr2n.wav\",\"source_type\":\"local-file\"}"
|
200
|
+
# }
|
201
|
+
# },
|
202
|
+
# "audio_vid": "v02870g10004cu8d4r7og65j2vr5opb0",
|
203
|
+
# "video_mode": 4
|
204
|
+
# }
|
205
|
+
# ]
|
206
|
+
# },
|
207
|
+
# "mode": "workbench",
|
208
|
+
# "history_option": {},
|
209
|
+
# "commerce_info": {
|
210
|
+
# "resource_id": "generate_video",
|
211
|
+
# "resource_id_type": "str",
|
212
|
+
# "resource_sub_type": "aigc",
|
213
|
+
# "benefit_type": "lip_sync_avatar_std", # 5积分
|
214
|
+
# # "benefit_type": "lip_sync_avatar_lively" # 10积分
|
215
|
+
# },
|
216
|
+
# "scene": "lip_sync_image",
|
217
|
+
# "client_trace_data": {},
|
218
|
+
# "submit_id_list": [
|
219
|
+
# str(uuid.uuid4())
|
220
|
+
# ]
|
221
|
+
# }
|
222
|
+
|
223
|
+
if request.image_url:
|
224
|
+
i2v_opt = {
|
225
|
+
"realman_avatar": {
|
226
|
+
"enable": True,
|
227
|
+
"origin_image": {
|
228
|
+
"image_uri": image_url,
|
229
|
+
"image_url": ""
|
230
|
+
},
|
231
|
+
"resource_id_loopy": resource_id_loopy,
|
232
|
+
"resource_id_std": resource_id_std,
|
233
|
+
"origin_audio": {
|
234
|
+
"vid": audio_vid
|
235
|
+
},
|
236
|
+
# "tts_info": "{\"name\":\"vyFWygmZsIZlUO4s0nr2n.wav\",\"source_type\":\"local-file\"}"
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
payload = {
|
241
|
+
"submit_id": "",
|
242
|
+
# "task_extra": "{\"promptSource\":\"photo_lip_sync\",\"generateTimes\":1,\"lipSyncInfo\":{\"sourceType\":\"local-file\",\"name\":\"vyFWygmZsIZlUO4s0nr2n.wav\"},\"isUseAiGenPrompt\":false,\"batchNumber\":1}",
|
243
|
+
"http_common_info": {
|
244
|
+
"aid": 513695
|
245
|
+
},
|
246
|
+
"input": {
|
247
|
+
"seed": 2032846910,
|
248
|
+
"video_gen_inputs": [
|
249
|
+
{
|
250
|
+
"v2v_opt": v2v_opt,
|
251
|
+
"i2v_opt": i2v_opt,
|
252
|
+
"audio_vid": audio_vid,
|
253
|
+
"video_mode": 4
|
254
|
+
}
|
255
|
+
]
|
256
|
+
},
|
257
|
+
"mode": "workbench",
|
258
|
+
"history_option": {},
|
259
|
+
"commerce_info": {
|
260
|
+
"resource_id": "generate_video",
|
261
|
+
"resource_id_type": "str",
|
262
|
+
"resource_sub_type": "aigc",
|
263
|
+
"benefit_type": model,
|
264
|
+
# "benefit_type": "lip_sync_avatar_lively" # 10积分
|
265
|
+
},
|
266
|
+
"scene": scene,
|
267
|
+
"client_trace_data": {},
|
268
|
+
"submit_id_list": [
|
269
|
+
str(uuid.uuid4())
|
270
|
+
]
|
271
|
+
}
|
272
|
+
|
273
|
+
logger.debug(bjson(payload))
|
274
|
+
|
275
|
+
async with httpx.AsyncClient(base_url=BASE_URL, headers=headers, timeout=60) as client:
|
276
|
+
response = await client.post(url, json=payload)
|
277
|
+
response.raise_for_status()
|
278
|
+
data = response.json()
|
279
|
+
logger.debug(bjson(data))
|
280
|
+
|
281
|
+
if task_ids := json_path(data, "$..task.task_id"):
|
282
|
+
task_id = task_ids[0]
|
283
|
+
return TaskResponse(task_id=task_id, system_fingerprint=token)
|
284
|
+
|
285
|
+
|
286
|
+
# {
|
287
|
+
# "submit_id": "740e28e3-12fd-4ab6-82da-7f2028ac6314",
|
288
|
+
# "task_extra": "{\"promptSource\":\"custom\",\"originSubmitId\":\"3575ebec-1d35-42f1-bd19-6cf0c8dee0b1\",\"isDefaultSeed\":1,\"originTemplateId\":\"\",\"imageNameMapping\":{},\"isUseAiGenPrompt\":false,\"batchNumber\":1}",
|
289
|
+
# "input": {
|
290
|
+
# "video_aspect_ratio": "16:9",
|
291
|
+
# "seed": 840565633,
|
292
|
+
# "video_gen_inputs": [
|
293
|
+
# {
|
294
|
+
# "prompt": "现代几何构图海报模板,庆祝男演员都市爱情剧《街角晚风》成功。画面分割为几个深红和灰色块面。一个灰色块内展示清晰的德塔文景气指数上升曲线图(深红线条)。一个色块放置男演员侧脸剧照。剧名和标语“人气飙升,全城热恋”分布在不同色块上,字体设计现代。整体风格简约、结构化、高级。",
|
295
|
+
# "fps": 24,
|
296
|
+
# "duration_ms": 5000,
|
297
|
+
# "video_mode": 2,
|
298
|
+
# "template_id": ""
|
299
|
+
# }
|
300
|
+
# ],
|
301
|
+
# "priority": 0,
|
302
|
+
# "model_req_key": "dreamina_ic_generate_video_model_vgfm_3.0"
|
303
|
+
# },
|
304
|
+
# "mode": "workbench",
|
305
|
+
# "history_option": {},
|
306
|
+
# "commerce_info": {
|
307
|
+
# "resource_id": "generate_video",
|
308
|
+
# "resource_id_type": "str",
|
309
|
+
# "resource_sub_type": "aigc",
|
310
|
+
# "benefit_type": "basic_video_operation_vgfm_v_three"
|
311
|
+
# },
|
312
|
+
# "client_trace_data": {}
|
313
|
+
# # }
|
314
|
+
|
315
|
+
if __name__ == '__main__':
|
316
|
+
token = "916fed81175f5186a2c05375699ea40d"
|
317
|
+
|
318
|
+
request = LipsyncVideoRequest(
|
319
|
+
model="lip_sync_avatar_std",
|
320
|
+
image_url="https://oss.ffire.cc/files/kling_watermark.png",
|
321
|
+
video_url="",
|
322
|
+
audio_url="https://oss.ffire.cc/files/lipsync.mp3"
|
323
|
+
)
|
324
|
+
|
325
|
+
# with timer():
|
326
|
+
# r = arun(create_realman_avatar(request.image_url, token))
|
327
|
+
# arun(get_task(r.task_id))
|
328
|
+
|
329
|
+
# image_uri = "tos-cn-i-tb4s082cfz/387649a361e546f89549bd3510ab926d"
|
330
|
+
# task_ids = arun(create_realman_avatar(image_uri, token="7c5e148d9fa858e3180c42f843c20454"))
|
331
|
+
# arun(mget_generate_task(task_ids))
|
332
|
+
with timer():
|
333
|
+
r = arun(create_task(request))
|
334
|
+
# arun(get_task(r.task_id))
|
meutils/data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2025.06.
|
1
|
+
2025.06.09.09.17.14
|
meutils/schemas/image_types.py
CHANGED
@@ -47,6 +47,7 @@ ASPECT_RATIOS = {
|
|
47
47
|
"768x1024": '3:4',
|
48
48
|
|
49
49
|
'1366x768': '16:9',
|
50
|
+
|
50
51
|
'768x1366': '9:16',
|
51
52
|
'1024x576': '16:9',
|
52
53
|
'576x1024': '9:16',
|
@@ -87,7 +88,7 @@ class ImageRequest(BaseModel): # openai
|
|
87
88
|
"""
|
88
89
|
图生图 两种方式: prompt + controls
|
89
90
|
"""
|
90
|
-
model: str
|
91
|
+
model: str
|
91
92
|
|
92
93
|
prompt: constr(min_length=1, max_length=3000) = ""
|
93
94
|
|
@@ -118,6 +119,7 @@ class ImageRequest(BaseModel): # openai
|
|
118
119
|
|
119
120
|
def __init__(self, /, **data: Any):
|
120
121
|
super().__init__(**data)
|
122
|
+
|
121
123
|
if self.aspect_ratio: # 适配比例
|
122
124
|
self.size = ASPECT_RATIOS.get(self.aspect_ratio, '1024x1024')
|
123
125
|
|
@@ -125,6 +127,9 @@ class ImageRequest(BaseModel): # openai
|
|
125
127
|
if ':' in self.size:
|
126
128
|
self.aspect_ratio = self.size
|
127
129
|
|
130
|
+
else:
|
131
|
+
self.aspect_ratio = ASPECT_RATIOS.get(self.size, '1:1')
|
132
|
+
|
128
133
|
self.size = self.size if 'x' in self.size else '512x512'
|
129
134
|
|
130
135
|
@cached_property
|
meutils/schemas/jimeng_types.py
CHANGED
@@ -12,6 +12,7 @@ import uuid
|
|
12
12
|
from meutils.pipe import *
|
13
13
|
|
14
14
|
BASE_URL = "https://jimeng.jianying.com"
|
15
|
+
BASE_URL_GLOBAL = "https://mweb-api-sg.capcut.com"
|
15
16
|
FEISHU_URL = "https://xchatllm.feishu.cn/sheets/GYCHsvI4qhnDPNtI4VPcdw2knEd?sheet=zkPAHw"
|
16
17
|
|
17
18
|
FEISHU_URL_MAPPER = {
|
meutils/schemas/oneapi/common.py
CHANGED
@@ -23,7 +23,7 @@ STEP = 2
|
|
23
23
|
MINIMAX_VIDEO = 3
|
24
24
|
|
25
25
|
MODEL_PRICE = {
|
26
|
-
"chatfire-claude":0.02,
|
26
|
+
"chatfire-claude": 0.02,
|
27
27
|
"o1:free": FREE,
|
28
28
|
# "claude-3-7-sonnet-code:free": "claude-3-7-sonnet-code"
|
29
29
|
"claude-3-7-sonnet-code:free": 0.0001,
|
@@ -33,6 +33,7 @@ MODEL_PRICE = {
|
|
33
33
|
|
34
34
|
"gpt-search": 0.02,
|
35
35
|
|
36
|
+
# 谷歌
|
36
37
|
"gemini-2.0-flash-search": 0.01,
|
37
38
|
"gemini-2.0-flash-exp-image-generation": 0.03,
|
38
39
|
|
@@ -43,7 +44,8 @@ MODEL_PRICE = {
|
|
43
44
|
"gemini-2.5-flash-video": 0.05,
|
44
45
|
"gemini-2.5-pro-video": 0.1,
|
45
46
|
|
46
|
-
"
|
47
|
+
"veo3": 4,
|
48
|
+
|
47
49
|
# rix
|
48
50
|
"kling_image": 0.05,
|
49
51
|
"kling_virtual_try_on": 1,
|
meutils/str_utils/__init__.py
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
from meutils.pipe import *
|
13
13
|
# from meutils.str_utils.translater import translater
|
14
14
|
from meutils.str_utils.regular_expression import parse_url
|
15
|
-
|
15
|
+
from meutils.caches import cache
|
16
16
|
from meutils.request_utils.crawler import Crawler
|
17
17
|
from urllib.parse import urlencode, parse_qs, parse_qsl, quote_plus, unquote_plus, urljoin
|
18
18
|
|
@@ -207,6 +207,40 @@ def unicode_normalize(s):
|
|
207
207
|
return unicodedata.normalize('NFKC', s)
|
208
208
|
|
209
209
|
|
210
|
+
def validate_url(url):
|
211
|
+
if isinstance(url, list):
|
212
|
+
return all(map(validate_url, url))
|
213
|
+
|
214
|
+
# 首先检查 URL 格式
|
215
|
+
try:
|
216
|
+
parsed_url = urlparse(url)
|
217
|
+
if not all([parsed_url.scheme, parsed_url.netloc]):
|
218
|
+
return False # , "URL 格式无效"
|
219
|
+
|
220
|
+
# 检查格式是否符合标准
|
221
|
+
if not re.match(r'^https?://', url):
|
222
|
+
return False # , "URL 必须以 http:// 或 https:// 开头"
|
223
|
+
except Exception:
|
224
|
+
|
225
|
+
logger.error("URL 解析错误")
|
226
|
+
return False
|
227
|
+
|
228
|
+
# 然后检查可访问性(可选)
|
229
|
+
try:
|
230
|
+
response = requests.head(url, timeout=5, allow_redirects=True)
|
231
|
+
if response.status_code >= 400:
|
232
|
+
logger.error(f"URL 返回错误状态码: {response.status_code}")
|
233
|
+
|
234
|
+
return False
|
235
|
+
|
236
|
+
logger.error("URL 有效")
|
237
|
+
return True
|
238
|
+
except requests.exceptions.RequestException as e:
|
239
|
+
logger.error(f"连接错误: {str(e)}")
|
240
|
+
|
241
|
+
return False
|
242
|
+
|
243
|
+
|
210
244
|
if __name__ == '__main__':
|
211
245
|
# print(str_replace('abcd', {'a': '8', 'd': '88'}))
|
212
246
|
# print(unquote())
|
@@ -231,8 +265,11 @@ if __name__ == '__main__':
|
|
231
265
|
|
232
266
|
print(parse_prompt("https://www.hao123.com/ hi" * 2, only_first_url=False))
|
233
267
|
|
234
|
-
# import chardet
|
235
|
-
#
|
236
|
-
# def detect_encoding(byte_content):
|
237
|
-
# result = chardet.detect(byte_content)
|
238
|
-
# return result['encoding']
|
268
|
+
# import chardet
|
269
|
+
#
|
270
|
+
# def detect_encoding(byte_content):
|
271
|
+
# result = chardet.detect(byte_content)
|
272
|
+
# return result['encoding']
|
273
|
+
|
274
|
+
url = 'https://fal.ai/models/fal-ai/flux-pro/kontext/requests/de5f28be-2ca8-4bd4-8c42-c7fc32969801?output=0'
|
275
|
+
print(validate_url([url] * 3))
|
@@ -174,3 +174,4 @@ if __name__ == '__main__':
|
|
174
174
|
https://p3-bot-workflow-sign.byteimg.com/tos-cn-i-mdko3gqilj/1fe07cca46224208bfbed8c0f3c50ed8.png~tplv-mdko3gqilj-image.image?rk3s=81d4c505&x-expires=1780112531&x-signature=e7q1NOMjqCHvMz%2FC3dVAEVisAh4%3D&x-wf-file_name=9748f6214970f744fe7fd7a3699cfa2.png \nA young woman holding a lipstick tube with a black body and gold decorative rings, featuring a nude or light brown lipstick bullet. The lipstick product faces the camera, positioned slightly below her face. In the background, a close-up of lips coated with the same nude or light brown shade, creating a natural and soft effect.
|
175
175
|
"""
|
176
176
|
print(parse_url(text, for_image=True))
|
177
|
+
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|