media-agent-mcp 0.3.9__py3-none-any.whl → 0.3.11__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.
- media_agent_mcp/async_server.py +48 -18
- {media_agent_mcp-0.3.9.dist-info → media_agent_mcp-0.3.11.dist-info}/METADATA +1 -1
- {media_agent_mcp-0.3.9.dist-info → media_agent_mcp-0.3.11.dist-info}/RECORD +6 -6
- {media_agent_mcp-0.3.9.dist-info → media_agent_mcp-0.3.11.dist-info}/WHEEL +0 -0
- {media_agent_mcp-0.3.9.dist-info → media_agent_mcp-0.3.11.dist-info}/entry_points.txt +0 -0
- {media_agent_mcp-0.3.9.dist-info → media_agent_mcp-0.3.11.dist-info}/top_level.txt +0 -0
media_agent_mcp/async_server.py
CHANGED
@@ -22,6 +22,27 @@ from typing import List, Optional
|
|
22
22
|
import json
|
23
23
|
from dotenv import load_dotenv
|
24
24
|
import uvicorn
|
25
|
+
from functools import wraps
|
26
|
+
|
27
|
+
def async_retry(max_retries=3, delay=2):
|
28
|
+
def decorator(func):
|
29
|
+
@wraps(func)
|
30
|
+
async def wrapper(*args, **kwargs):
|
31
|
+
for attempt in range(max_retries):
|
32
|
+
try:
|
33
|
+
result = await func(*args, **kwargs)
|
34
|
+
if isinstance(result, dict) and result.get('status') == 'error':
|
35
|
+
logger.warning(f"Attempt {attempt + 1} of {max_retries} failed for {func.__name__}. Error: {result.get('message')}. Retrying in {delay}s...")
|
36
|
+
await asyncio.sleep(delay)
|
37
|
+
continue
|
38
|
+
return result
|
39
|
+
except Exception as e:
|
40
|
+
logger.error(f"Attempt {attempt + 1} of {max_retries} failed for {func.__name__} with exception: {e}. Retrying in {delay}s...")
|
41
|
+
await asyncio.sleep(delay)
|
42
|
+
logger.error(f"Function {func.__name__} failed after {max_retries} retries.")
|
43
|
+
return {"status": "error", "data": None, "message": f"Function {func.__name__} failed after {max_retries} retries."}
|
44
|
+
return wrapper
|
45
|
+
return decorator
|
25
46
|
|
26
47
|
from mcp.server.fastmcp import FastMCP
|
27
48
|
|
@@ -49,7 +70,8 @@ mcp = FastMCP("Media-Agent-MCP-Async")
|
|
49
70
|
|
50
71
|
|
51
72
|
@mcp.tool()
|
52
|
-
|
73
|
+
@async_retry()
|
74
|
+
async def video_concat_tool(video_urls: List[str]) -> dict:
|
53
75
|
"""
|
54
76
|
Asynchronously concatenate multiple videos from URLs and upload to TOS.
|
55
77
|
|
@@ -57,13 +79,14 @@ async def video_concat_tool(video_urls: List[str]) -> str:
|
|
57
79
|
video_urls: List of video URLs to concatenate in order
|
58
80
|
|
59
81
|
Returns:
|
60
|
-
|
82
|
+
Dictionary with status, data, and message
|
61
83
|
"""
|
62
84
|
return await async_video_concat_tool(video_urls)
|
63
85
|
|
64
86
|
|
65
87
|
@mcp.tool()
|
66
|
-
|
88
|
+
@async_retry()
|
89
|
+
async def video_last_frame_tool(video_url: str) -> dict:
|
67
90
|
"""
|
68
91
|
Asynchronously extract the last frame from a video file and upload to TOS.
|
69
92
|
|
@@ -71,13 +94,14 @@ async def video_last_frame_tool(video_url: str) -> str:
|
|
71
94
|
video_url: URL or path to the video file
|
72
95
|
|
73
96
|
Returns:
|
74
|
-
|
97
|
+
Dictionary with status, data, and message
|
75
98
|
"""
|
76
99
|
return await async_video_last_frame_tool(video_url)
|
77
100
|
|
78
101
|
|
79
102
|
@mcp.tool()
|
80
|
-
|
103
|
+
@async_retry()
|
104
|
+
async def seedream_generate_image_tool(prompt: str, size: str = "1024x1024") -> dict:
|
81
105
|
"""
|
82
106
|
Asynchronously generate an image using Seedream AI model.
|
83
107
|
|
@@ -86,15 +110,16 @@ async def seedream_generate_image_tool(prompt: str, size: str = "1024x1024") ->
|
|
86
110
|
size: Size of the image (e.g., "1024x1024")
|
87
111
|
|
88
112
|
Returns:
|
89
|
-
|
113
|
+
Dictionary with status, data, and message
|
90
114
|
"""
|
91
115
|
return await async_seedream_generate_image_tool(prompt, size)
|
92
116
|
|
93
117
|
|
94
118
|
@mcp.tool()
|
119
|
+
@async_retry()
|
95
120
|
async def seedance_generate_video_tool(prompt: str, first_frame_image: str,
|
96
121
|
last_frame_image: str = None, duration: int = 5,
|
97
|
-
resolution: str = "720p") ->
|
122
|
+
resolution: str = "720p") -> dict:
|
98
123
|
"""
|
99
124
|
Asynchronously generate a video using Seedance AI model with first/last frame images.
|
100
125
|
|
@@ -106,14 +131,15 @@ async def seedance_generate_video_tool(prompt: str, first_frame_image: str,
|
|
106
131
|
resolution: Video resolution (480p, 720p)
|
107
132
|
|
108
133
|
Returns:
|
109
|
-
|
134
|
+
Dictionary with status, data, and message
|
110
135
|
"""
|
111
136
|
return await async_seedance_generate_video_tool(prompt, first_frame_image, last_frame_image, duration, resolution)
|
112
137
|
|
113
138
|
|
114
139
|
@mcp.tool()
|
140
|
+
@async_retry()
|
115
141
|
async def seededit_tool(image_url: str, prompt: str, seed: int = -1,
|
116
|
-
scale: float = 0.5, charactor_keep: bool = False) ->
|
142
|
+
scale: float = 0.5, charactor_keep: bool = False) -> dict:
|
117
143
|
"""
|
118
144
|
Asynchronously edit an image using Seededit model.
|
119
145
|
|
@@ -125,13 +151,14 @@ async def seededit_tool(image_url: str, prompt: str, seed: int = -1,
|
|
125
151
|
charactor_keep: whether to keep the main character in this image, if you wanna change the main character, please keep False
|
126
152
|
|
127
153
|
Returns:
|
128
|
-
|
154
|
+
Dictionary with status, data, and message
|
129
155
|
"""
|
130
156
|
return await async_seededit_tool(image_url, prompt, seed, scale, charactor_keep)
|
131
157
|
|
132
158
|
|
133
159
|
@mcp.tool()
|
134
|
-
|
160
|
+
@async_retry()
|
161
|
+
async def vlm_vision_task_tool(messages: List) -> dict:
|
135
162
|
"""
|
136
163
|
Asynchronously perform vision-language tasks using VLM model.
|
137
164
|
|
@@ -139,13 +166,14 @@ async def vlm_vision_task_tool(messages: List) -> str:
|
|
139
166
|
messages: OpenAI-compatible messages format
|
140
167
|
|
141
168
|
Returns:
|
142
|
-
|
169
|
+
Dictionary with status, data, and message
|
143
170
|
"""
|
144
171
|
return await async_vlm_vision_task_tool(messages)
|
145
172
|
|
146
173
|
|
147
174
|
@mcp.tool()
|
148
|
-
|
175
|
+
@async_retry()
|
176
|
+
async def image_selector_tool(image_paths: List[str], prompt: str) -> dict:
|
149
177
|
"""
|
150
178
|
Asynchronously select the best image from multiple options using VLM model.
|
151
179
|
|
@@ -154,13 +182,14 @@ async def image_selector_tool(image_paths: List[str], prompt: str) -> str:
|
|
154
182
|
prompt: Selection criteria prompt
|
155
183
|
|
156
184
|
Returns:
|
157
|
-
|
185
|
+
Dictionary with status, data, and message
|
158
186
|
"""
|
159
187
|
return await async_image_selector_tool(image_paths, prompt)
|
160
188
|
|
161
189
|
|
162
190
|
@mcp.tool()
|
163
|
-
|
191
|
+
@async_retry()
|
192
|
+
async def video_selector_tool(video_paths: List[str], prompt: str) -> dict:
|
164
193
|
"""
|
165
194
|
Asynchronously select the best video from multiple options using VLM model.
|
166
195
|
|
@@ -169,14 +198,15 @@ async def video_selector_tool(video_paths: List[str], prompt: str) -> str:
|
|
169
198
|
prompt: Selection criteria prompt
|
170
199
|
|
171
200
|
Returns:
|
172
|
-
|
201
|
+
Dictionary with status, data, and message
|
173
202
|
"""
|
174
203
|
return await async_video_selector_tool(video_paths, prompt)
|
175
204
|
|
176
205
|
|
177
206
|
@mcp.tool()
|
207
|
+
@async_retry()
|
178
208
|
async def tos_save_content_tool(content: str, file_extension: str = "txt",
|
179
|
-
object_key: Optional[str] = None) ->
|
209
|
+
object_key: Optional[str] = None) -> dict:
|
180
210
|
"""
|
181
211
|
Asynchronously save content to TOS and return URL.
|
182
212
|
|
@@ -186,7 +216,7 @@ async def tos_save_content_tool(content: str, file_extension: str = "txt",
|
|
186
216
|
object_key: Optional key to use for the object in TOS
|
187
217
|
|
188
218
|
Returns:
|
189
|
-
|
219
|
+
Dictionary with status, data, and message
|
190
220
|
"""
|
191
221
|
return await async_tos_save_content_tool(content, file_extension, object_key)
|
192
222
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
media_agent_mcp/__init__.py,sha256=4kV5u8kHrsdjpMHDNUhc8h4U6AwOyw1mNptFPd2snrQ,365
|
2
|
-
media_agent_mcp/async_server.py,sha256=
|
2
|
+
media_agent_mcp/async_server.py,sha256=IpXezeefilGukutgBqOU7RvCDp-t9_j11A2OOqiu2z0,10524
|
3
3
|
media_agent_mcp/async_wrapper.py,sha256=bHi0cCKxv6R9oHcNcNq8tV0AyKrTDV47s8BuWetqlIg,8992
|
4
4
|
media_agent_mcp/server.py,sha256=-mTeNcJXIlgByCG2HhaqV6zSbhjrQIEv_ssLN47KAzM,13759
|
5
5
|
media_agent_mcp/ai_models/__init__.py,sha256=WN8JDSJbj2-sNwaQg3MDwmm9mvJTC1mqpWliac3sHoc,427
|
@@ -14,8 +14,8 @@ media_agent_mcp/storage/__init__.py,sha256=eio7ZiSeLjCxICSZwZisiR7wKJfXlT2PV7aDE
|
|
14
14
|
media_agent_mcp/storage/tos_client.py,sha256=9c3GPmQe2stvxgZzsWYjVqKzVyvluZqYneCXYj-FQ3M,3174
|
15
15
|
media_agent_mcp/video/__init__.py,sha256=4ILnqYaUaYKI4GWOSg2SNZqt10UM1Y-8Q2SVvjoijqY,277
|
16
16
|
media_agent_mcp/video/processor.py,sha256=5ABPyj1IoD2xyIiB8dkEx4ZssPTXKHtuoFjy-dmnFks,11866
|
17
|
-
media_agent_mcp-0.3.
|
18
|
-
media_agent_mcp-0.3.
|
19
|
-
media_agent_mcp-0.3.
|
20
|
-
media_agent_mcp-0.3.
|
21
|
-
media_agent_mcp-0.3.
|
17
|
+
media_agent_mcp-0.3.11.dist-info/METADATA,sha256=92jf-Ti8koiMfQqYbpcFNwNVQ4sntuCz0XrRTnBe0rI,10976
|
18
|
+
media_agent_mcp-0.3.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
19
|
+
media_agent_mcp-0.3.11.dist-info/entry_points.txt,sha256=qhOUwR-ORVf9GO7emhhl7Lgd6MISgqbZr8bEuSH_VdA,70
|
20
|
+
media_agent_mcp-0.3.11.dist-info/top_level.txt,sha256=WEa0YfchpTxZgiKn8gdxYgs-dir5HepJaTOrxAGx9nY,16
|
21
|
+
media_agent_mcp-0.3.11.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|