media-agent-mcp 0.3.10__py3-none-any.whl → 0.4.0__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/ai_models/openaiedit.py +89 -0
- media_agent_mcp/ai_models/seededit.py +52 -3
- media_agent_mcp/async_server.py +56 -37
- media_agent_mcp/async_wrapper.py +17 -10
- media_agent_mcp/media_selectors/image_selector.py +3 -0
- media_agent_mcp/media_selectors/video_selector.py +3 -0
- {media_agent_mcp-0.3.10.dist-info → media_agent_mcp-0.4.0.dist-info}/METADATA +2 -2
- media_agent_mcp-0.4.0.dist-info/RECORD +22 -0
- media_agent_mcp-0.3.10.dist-info/RECORD +0 -21
- {media_agent_mcp-0.3.10.dist-info → media_agent_mcp-0.4.0.dist-info}/WHEEL +0 -0
- {media_agent_mcp-0.3.10.dist-info → media_agent_mcp-0.4.0.dist-info}/entry_points.txt +0 -0
- {media_agent_mcp-0.3.10.dist-info → media_agent_mcp-0.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
import os
|
2
|
+
from typing import Dict, Any
|
3
|
+
import openai
|
4
|
+
import requests
|
5
|
+
from PIL import Image
|
6
|
+
from io import BytesIO
|
7
|
+
import tempfile
|
8
|
+
import os
|
9
|
+
from urllib.parse import urlparse
|
10
|
+
|
11
|
+
def openaiedit(image_url: str, prompt: str, size: str = "1024x1024") -> Dict[str, Any]:
|
12
|
+
"""
|
13
|
+
Perform image editing using the OpenAI Images API.
|
14
|
+
|
15
|
+
:param image_url: URL of the input image.
|
16
|
+
:param prompt: The editing prompt.
|
17
|
+
:param size: The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024".
|
18
|
+
:return: JSON response with status, data (image URL), and message.
|
19
|
+
"""
|
20
|
+
try:
|
21
|
+
client = openai.OpenAI(
|
22
|
+
api_key='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'
|
23
|
+
)
|
24
|
+
|
25
|
+
# Download the image
|
26
|
+
response = requests.get(image_url)
|
27
|
+
response.raise_for_status()
|
28
|
+
|
29
|
+
# Save image to a temporary file
|
30
|
+
parsed_url = urlparse(image_url)
|
31
|
+
file_ext = os.path.splitext(parsed_url.path)[1]
|
32
|
+
if not file_ext:
|
33
|
+
# Fallback if extension is not in URL path
|
34
|
+
content_type = response.headers.get('content-type')
|
35
|
+
if content_type and 'image' in content_type:
|
36
|
+
file_ext = '.' + content_type.split('/')[1]
|
37
|
+
else:
|
38
|
+
file_ext = '.png' # default
|
39
|
+
|
40
|
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=file_ext)
|
41
|
+
try:
|
42
|
+
temp_file.write(response.content)
|
43
|
+
temp_file.close()
|
44
|
+
|
45
|
+
# Call OpenAI API with the local file
|
46
|
+
with open(temp_file.name, "rb") as f:
|
47
|
+
response = client.images.edit(
|
48
|
+
model="gpt-image-1",
|
49
|
+
image=f,
|
50
|
+
prompt=prompt,
|
51
|
+
n=1,
|
52
|
+
size=size
|
53
|
+
)
|
54
|
+
finally:
|
55
|
+
os.unlink(temp_file.name) # Clean up the temporary file
|
56
|
+
|
57
|
+
image_url = response.data[0].url
|
58
|
+
|
59
|
+
return {
|
60
|
+
"status": "success",
|
61
|
+
"data": {"image_url": image_url},
|
62
|
+
"message": "Image edited successfully."
|
63
|
+
}
|
64
|
+
except openai.APIError as e:
|
65
|
+
return {
|
66
|
+
"status": "error",
|
67
|
+
"data": None,
|
68
|
+
"message": f"OpenAI API Error: {e}"
|
69
|
+
}
|
70
|
+
except requests.RequestException as e:
|
71
|
+
return {
|
72
|
+
"status": "error",
|
73
|
+
"data": None,
|
74
|
+
"message": f"Error downloading image: {e}"
|
75
|
+
}
|
76
|
+
except Exception as e:
|
77
|
+
return {
|
78
|
+
"status": "error",
|
79
|
+
"data": None,
|
80
|
+
"message": f"An unexpected error occurred: {e}"
|
81
|
+
}
|
82
|
+
|
83
|
+
if __name__ == '__main__':
|
84
|
+
# Make sure to set your OPENAI_API_KEY environment variable
|
85
|
+
# For example: export OPENAI_API_KEY='your-api-key'
|
86
|
+
image_url = 'https://carey.tos-ap-southeast-1.bytepluses.com/Art%20Portrait/Art%20Portrait/Art%20Portrait/Art%20Portrait%20(1).jpg'
|
87
|
+
prompt = 'A cute baby sea otter cooking a meal'
|
88
|
+
result = openaiedit(image_url, prompt)
|
89
|
+
print(result)
|
@@ -1,7 +1,20 @@
|
|
1
1
|
import os
|
2
|
+
import tempfile
|
2
3
|
from typing import Dict, Any
|
4
|
+
|
5
|
+
import requests
|
3
6
|
from volcengine.visual.VisualService import VisualService
|
4
7
|
|
8
|
+
try:
|
9
|
+
from ..storage.tos_client import upload_to_tos
|
10
|
+
except (ImportError, ValueError):
|
11
|
+
# This fallback is for running the script directly
|
12
|
+
import sys
|
13
|
+
import os
|
14
|
+
|
15
|
+
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
|
16
|
+
from media_agent_mcp.storage.tos_client import upload_to_tos
|
17
|
+
|
5
18
|
|
6
19
|
def parse_seededit_response(response) -> Dict[str, Any]:
|
7
20
|
"""
|
@@ -44,7 +57,7 @@ def parse_seededit_response(response) -> Dict[str, Any]:
|
|
44
57
|
|
45
58
|
def seededit(image_url, prompt, charactor_keep=False, return_url=True, scale=1, seed=-1) -> Dict[str, Any]:
|
46
59
|
"""
|
47
|
-
Perform image editing using the VisualService.
|
60
|
+
Perform image editing using the VisualService, then upload the result to TOS.
|
48
61
|
|
49
62
|
:param image_url: URL of the input image.
|
50
63
|
:param prompt: The editing prompt.
|
@@ -52,7 +65,7 @@ def seededit(image_url, prompt, charactor_keep=False, return_url=True, scale=1,
|
|
52
65
|
:param return_url: Whether to return image URL or base64 string.
|
53
66
|
:param scale: Text influence scale (0.1-1.0).
|
54
67
|
:param seed: Random seed for reproducibility.
|
55
|
-
:return: JSON response with status, data (
|
68
|
+
:return: JSON response with status, data (TOS URL), and message.
|
56
69
|
"""
|
57
70
|
try:
|
58
71
|
visual_service = VisualService()
|
@@ -81,7 +94,43 @@ def seededit(image_url, prompt, charactor_keep=False, return_url=True, scale=1,
|
|
81
94
|
}
|
82
95
|
|
83
96
|
response = visual_service.cv_process(form)
|
84
|
-
|
97
|
+
parsed_response = parse_seededit_response(response)
|
98
|
+
|
99
|
+
if parsed_response['status'] == 'success':
|
100
|
+
generated_image_url = parsed_response['data']['image_url']
|
101
|
+
|
102
|
+
# Download the image from the URL
|
103
|
+
try:
|
104
|
+
image_response = requests.get(generated_image_url, stream=True)
|
105
|
+
image_response.raise_for_status() # Raise an exception for bad status codes
|
106
|
+
except requests.exceptions.RequestException as e:
|
107
|
+
return {"status": "error", "data": None, "message": f"Failed to download image: {e}"}
|
108
|
+
|
109
|
+
# Create a temporary file to save the image
|
110
|
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") as temp_file:
|
111
|
+
for chunk in image_response.iter_content(chunk_size=8192):
|
112
|
+
temp_file.write(chunk)
|
113
|
+
temp_file_path = temp_file.name
|
114
|
+
|
115
|
+
try:
|
116
|
+
# Upload the temporary file to TOS
|
117
|
+
tos_response = upload_to_tos(temp_file_path)
|
118
|
+
# The URL is in tos_response['data']['url']
|
119
|
+
# The final response should be compatible with other tools
|
120
|
+
if tos_response['status'] == 'success':
|
121
|
+
return {
|
122
|
+
"status": "success",
|
123
|
+
"data": {"image_url": tos_response['data']['url']},
|
124
|
+
"message": "Image edited and uploaded to TOS successfully"
|
125
|
+
}
|
126
|
+
else:
|
127
|
+
return tos_response
|
128
|
+
finally:
|
129
|
+
# Clean up the temporary file
|
130
|
+
os.remove(temp_file_path)
|
131
|
+
else:
|
132
|
+
return parsed_response
|
133
|
+
|
85
134
|
except Exception as e:
|
86
135
|
return {
|
87
136
|
"status": "error",
|
media_agent_mcp/async_server.py
CHANGED
@@ -22,32 +22,38 @@ from typing import List, Optional
|
|
22
22
|
import json
|
23
23
|
from dotenv import load_dotenv
|
24
24
|
import uvicorn
|
25
|
-
from
|
26
|
-
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
36
46
|
|
37
47
|
from mcp.server.fastmcp import FastMCP
|
38
48
|
|
39
49
|
# Import async wrappers
|
40
50
|
from media_agent_mcp.async_wrapper import (
|
41
|
-
async_video_concat_tool,
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
async_image_selector_tool,
|
48
|
-
async_video_selector_tool,
|
49
|
-
async_tos_save_content_tool,
|
50
|
-
cleanup_executor
|
51
|
+
async_video_concat_tool, async_video_last_frame_tool,
|
52
|
+
async_seedream_generate_image_tool, async_seedance_generate_video_tool,
|
53
|
+
async_seededit_tool, async_vlm_vision_task_tool,
|
54
|
+
async_image_selector_tool, async_video_selector_tool,
|
55
|
+
async_tos_save_content_tool, cleanup_executor,
|
56
|
+
async_openaiedit_tool
|
51
57
|
)
|
52
58
|
|
53
59
|
# Configure logging
|
@@ -60,7 +66,7 @@ mcp = FastMCP("Media-Agent-MCP-Async")
|
|
60
66
|
|
61
67
|
|
62
68
|
@mcp.tool()
|
63
|
-
@
|
69
|
+
@async_retry()
|
64
70
|
async def video_concat_tool(video_urls: List[str]) -> dict:
|
65
71
|
"""
|
66
72
|
Asynchronously concatenate multiple videos from URLs and upload to TOS.
|
@@ -75,7 +81,7 @@ async def video_concat_tool(video_urls: List[str]) -> dict:
|
|
75
81
|
|
76
82
|
|
77
83
|
@mcp.tool()
|
78
|
-
@
|
84
|
+
@async_retry()
|
79
85
|
async def video_last_frame_tool(video_url: str) -> dict:
|
80
86
|
"""
|
81
87
|
Asynchronously extract the last frame from a video file and upload to TOS.
|
@@ -90,7 +96,7 @@ async def video_last_frame_tool(video_url: str) -> dict:
|
|
90
96
|
|
91
97
|
|
92
98
|
@mcp.tool()
|
93
|
-
@
|
99
|
+
@async_retry()
|
94
100
|
async def seedream_generate_image_tool(prompt: str, size: str = "1024x1024") -> dict:
|
95
101
|
"""
|
96
102
|
Asynchronously generate an image using Seedream AI model.
|
@@ -106,7 +112,7 @@ async def seedream_generate_image_tool(prompt: str, size: str = "1024x1024") ->
|
|
106
112
|
|
107
113
|
|
108
114
|
@mcp.tool()
|
109
|
-
@
|
115
|
+
@async_retry()
|
110
116
|
async def seedance_generate_video_tool(prompt: str, first_frame_image: str,
|
111
117
|
last_frame_image: str = None, duration: int = 5,
|
112
118
|
resolution: str = "720p") -> dict:
|
@@ -127,27 +133,40 @@ async def seedance_generate_video_tool(prompt: str, first_frame_image: str,
|
|
127
133
|
|
128
134
|
|
129
135
|
@mcp.tool()
|
130
|
-
@
|
131
|
-
async def seededit_tool(image_url: str, prompt: str
|
132
|
-
scale: float = 0.5, charactor_keep: bool = False) -> dict:
|
136
|
+
@async_retry()
|
137
|
+
async def seededit_tool(image_url: str, prompt: str) -> dict:
|
133
138
|
"""
|
134
|
-
Asynchronously edit an image using
|
139
|
+
Asynchronously edit an image using the OpenAI Images API.
|
135
140
|
|
136
141
|
Args:
|
137
142
|
image_url: Input image URL for editing
|
138
143
|
prompt: Text prompt for image editing
|
139
|
-
seed: Random seed for reproducibility (-1 for random)
|
140
|
-
scale: Influence degree of text description (0-1)
|
141
|
-
charactor_keep: whether to keep the main character in this image, if you wanna change the main character, please keep False
|
142
144
|
|
143
145
|
Returns:
|
144
146
|
Dictionary with status, data, and message
|
145
147
|
"""
|
146
|
-
return await async_seededit_tool(image_url, prompt
|
148
|
+
return await async_seededit_tool(image_url, prompt)
|
147
149
|
|
148
150
|
|
149
151
|
@mcp.tool()
|
150
|
-
@
|
152
|
+
@async_retry()
|
153
|
+
async def openaiedit_tool(image_url: str, prompt: str, size: str = "1024x1024") -> dict:
|
154
|
+
"""
|
155
|
+
Asynchronously edit an image using the OpenAI Images API.
|
156
|
+
|
157
|
+
Args:
|
158
|
+
image_url: Input image URL for editing
|
159
|
+
prompt: Text prompt for image editing
|
160
|
+
size: The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024".
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
Dictionary with status, data, and message
|
164
|
+
"""
|
165
|
+
return await async_openaiedit_tool(image_url, prompt, size)
|
166
|
+
|
167
|
+
|
168
|
+
@mcp.tool()
|
169
|
+
@async_retry()
|
151
170
|
async def vlm_vision_task_tool(messages: List) -> dict:
|
152
171
|
"""
|
153
172
|
Asynchronously perform vision-language tasks using VLM model.
|
@@ -162,7 +181,7 @@ async def vlm_vision_task_tool(messages: List) -> dict:
|
|
162
181
|
|
163
182
|
|
164
183
|
@mcp.tool()
|
165
|
-
@
|
184
|
+
@async_retry()
|
166
185
|
async def image_selector_tool(image_paths: List[str], prompt: str) -> dict:
|
167
186
|
"""
|
168
187
|
Asynchronously select the best image from multiple options using VLM model.
|
@@ -178,7 +197,7 @@ async def image_selector_tool(image_paths: List[str], prompt: str) -> dict:
|
|
178
197
|
|
179
198
|
|
180
199
|
@mcp.tool()
|
181
|
-
@
|
200
|
+
@async_retry()
|
182
201
|
async def video_selector_tool(video_paths: List[str], prompt: str) -> dict:
|
183
202
|
"""
|
184
203
|
Asynchronously select the best video from multiple options using VLM model.
|
@@ -194,7 +213,7 @@ async def video_selector_tool(video_paths: List[str], prompt: str) -> dict:
|
|
194
213
|
|
195
214
|
|
196
215
|
@mcp.tool()
|
197
|
-
@
|
216
|
+
@async_retry()
|
198
217
|
async def tos_save_content_tool(content: str, file_extension: str = "txt",
|
199
218
|
object_key: Optional[str] = None) -> dict:
|
200
219
|
"""
|
media_agent_mcp/async_wrapper.py
CHANGED
@@ -18,6 +18,7 @@ from media_agent_mcp.video import concat_videos, extract_last_frame
|
|
18
18
|
from media_agent_mcp.ai_models.seedream import generate_image
|
19
19
|
from media_agent_mcp.ai_models.seedance import generate_video
|
20
20
|
from media_agent_mcp.ai_models.seededit import seededit
|
21
|
+
from media_agent_mcp.ai_models.openaiedit import openaiedit
|
21
22
|
from media_agent_mcp.media_selectors.image_selector import select_best_image
|
22
23
|
from media_agent_mcp.media_selectors.video_selector import select_best_video
|
23
24
|
|
@@ -128,16 +129,11 @@ def _sync_seedance_generate_video(prompt: str, first_frame_image: str,
|
|
128
129
|
|
129
130
|
@async_wrapper
|
130
131
|
@json_response_wrapper
|
131
|
-
def _sync_seededit(image_url: str, prompt: str
|
132
|
-
scale: float = 0.5, charactor_keep: bool = False) -> str:
|
132
|
+
def _sync_seededit(image_url: str, prompt: str) -> str:
|
133
133
|
"""Synchronous image editing wrapper."""
|
134
134
|
return seededit(
|
135
135
|
image_url=image_url,
|
136
|
-
prompt=prompt
|
137
|
-
charactor_keep=charactor_keep,
|
138
|
-
return_url=True,
|
139
|
-
scale=scale,
|
140
|
-
seed=seed
|
136
|
+
prompt=prompt
|
141
137
|
)
|
142
138
|
|
143
139
|
|
@@ -238,10 +234,10 @@ async def async_seedance_generate_video_tool(prompt: str, first_frame_image: str
|
|
238
234
|
return await _sync_seedance_generate_video(prompt, first_frame_image, last_frame_image, duration, resolution)
|
239
235
|
|
240
236
|
|
241
|
-
async def async_seededit_tool(image_url: str, prompt: str
|
242
|
-
scale: float = 0.5, charactor_keep: bool = False) -> str:
|
237
|
+
async def async_seededit_tool(image_url: str, prompt: str) -> str:
|
243
238
|
"""Async image editing tool."""
|
244
|
-
|
239
|
+
result = await _sync_seededit(image_url, prompt)
|
240
|
+
return json.loads(result)
|
245
241
|
|
246
242
|
|
247
243
|
async def async_vlm_vision_task_tool(messages: List) -> str:
|
@@ -258,6 +254,17 @@ async def async_video_selector_tool(video_paths: List[str], prompt: str) -> str:
|
|
258
254
|
"""Async video selector tool."""
|
259
255
|
return await _sync_video_selector(video_paths, prompt)
|
260
256
|
|
257
|
+
@async_wrapper
|
258
|
+
@json_response_wrapper
|
259
|
+
def _sync_openaiedit(image_url: str, prompt: str, size: str = "1024x1024") -> str:
|
260
|
+
"""Synchronous image editing wrapper for openaiedit."""
|
261
|
+
return openaiedit(image_url=image_url, prompt=prompt, size=size)
|
262
|
+
|
263
|
+
async def async_openaiedit_tool(image_url: str, prompt: str, size: str = "1024x1024") -> str:
|
264
|
+
"""Async image editing tool for openaiedit."""
|
265
|
+
result = await _sync_openaiedit(image_url, prompt, size)
|
266
|
+
return json.loads(result)
|
267
|
+
|
261
268
|
|
262
269
|
async def async_tos_save_content_tool(content: str, file_extension: str = "txt",
|
263
270
|
object_key: Optional[str] = None) -> str:
|
@@ -76,6 +76,7 @@ def select_best_image(image_urls: List[str], prompt: str) -> dict:
|
|
76
76
|
except Exception as e:
|
77
77
|
logger.error(f"[VLM]Error selecting image: {e}")
|
78
78
|
return {
|
79
|
+
"status": "error",
|
79
80
|
"choice": None,
|
80
81
|
"reason": f"Error selecting image: {str(e)}",
|
81
82
|
"url": image_urls[0] if image_urls else None
|
@@ -94,6 +95,7 @@ def select_best_image(image_urls: List[str], prompt: str) -> dict:
|
|
94
95
|
except Exception as e:
|
95
96
|
logger.error(f"[VLM]Error parsing response: {e}")
|
96
97
|
return {
|
98
|
+
"status": "error",
|
97
99
|
"choice": None,
|
98
100
|
"reason": f"Error parsing response: {str(e)}",
|
99
101
|
"url": image_urls[0]
|
@@ -102,6 +104,7 @@ def select_best_image(image_urls: List[str], prompt: str) -> dict:
|
|
102
104
|
except Exception as e:
|
103
105
|
logger.error(f"Error selecting image: {e}")
|
104
106
|
return {
|
107
|
+
"status": "error",
|
105
108
|
"choice": None,
|
106
109
|
"reason": f"Error selecting image: {str(e)}",
|
107
110
|
"url": image_urls[0] if image_urls else None
|
@@ -116,6 +116,7 @@ def select_best_video(video_urls: List[str], prompt: str) -> dict:
|
|
116
116
|
except Exception as e:
|
117
117
|
logger.error(f"[VLM]Error selecting image: {e}")
|
118
118
|
return {
|
119
|
+
"status": "error",
|
119
120
|
"choice": None,
|
120
121
|
"reason": f"Error selecting image: {str(e)}",
|
121
122
|
"url": video_urls[0] if video_urls else None
|
@@ -134,6 +135,7 @@ def select_best_video(video_urls: List[str], prompt: str) -> dict:
|
|
134
135
|
except Exception as e:
|
135
136
|
logger.error(f"[VLM]Error parsing response: {e}")
|
136
137
|
return {
|
138
|
+
"status": "error",
|
137
139
|
"choice": None,
|
138
140
|
"reason": f"Error parsing response: {str(e)}",
|
139
141
|
"url": video_urls[0]
|
@@ -142,6 +144,7 @@ def select_best_video(video_urls: List[str], prompt: str) -> dict:
|
|
142
144
|
except Exception as e:
|
143
145
|
logger.error(f"Error selecting image: {e}")
|
144
146
|
return {
|
147
|
+
"status": "error",
|
145
148
|
"choice": None,
|
146
149
|
"reason": f"Error selecting image: {str(e)}",
|
147
150
|
"url": video_urls[0] if video_urls else None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: media-agent-mcp
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.0
|
4
4
|
Summary: A Model Context Protocol server for media processing with AI tools
|
5
5
|
Author-email: Media Agent Team <team@mediaagent.com>
|
6
6
|
Keywords: mcp,ai,media,video,image,processing
|
@@ -22,7 +22,7 @@ Requires-Dist: numpy>=1.24.0
|
|
22
22
|
Requires-Dist: python-dotenv>=1.0.0
|
23
23
|
Requires-Dist: volcengine-python-sdk>=1.0.0
|
24
24
|
Requires-Dist: volcengine>=1.0.194
|
25
|
-
Requires-Dist:
|
25
|
+
Requires-Dist: openai>=1.97.1
|
26
26
|
|
27
27
|
# Media Agent MCP
|
28
28
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
media_agent_mcp/__init__.py,sha256=4kV5u8kHrsdjpMHDNUhc8h4U6AwOyw1mNptFPd2snrQ,365
|
2
|
+
media_agent_mcp/async_server.py,sha256=W3NOiinhBRqJg0DXgAEcAZtiHHeSd9Xky-v15QL4xc0,10706
|
3
|
+
media_agent_mcp/async_wrapper.py,sha256=OWTRPiYQIWf8CpE8PMT-WJocirxCy2tN-FbFEdFtWqI,9258
|
4
|
+
media_agent_mcp/server.py,sha256=-mTeNcJXIlgByCG2HhaqV6zSbhjrQIEv_ssLN47KAzM,13759
|
5
|
+
media_agent_mcp/ai_models/__init__.py,sha256=WN8JDSJbj2-sNwaQg3MDwmm9mvJTC1mqpWliac3sHoc,427
|
6
|
+
media_agent_mcp/ai_models/openaiedit.py,sha256=UbAhAlv-c3jQ5Av1Y-1YWzSEUrTKL21YB8V2NDPGL0A,3099
|
7
|
+
media_agent_mcp/ai_models/seed16.py,sha256=P3KHNF_SfLryJz6qFP7UUtBfw_28ubdrj2lJkt3WsY8,4989
|
8
|
+
media_agent_mcp/ai_models/seedance.py,sha256=fv7hdxlwRtFqMnOG9o7Kx_-k2ihB6VBgN3wCoo-Y-Qs,9024
|
9
|
+
media_agent_mcp/ai_models/seededit.py,sha256=KO0cWBF5c1hHkdzMw_qTXxYf2PpoSpZ4q8uJnaDIt7U,5281
|
10
|
+
media_agent_mcp/ai_models/seedream.py,sha256=lKWMRzV-ZjZ2JB93A3XYUOF7QfzP3zFMQleBtEOkuW8,4467
|
11
|
+
media_agent_mcp/media_selectors/__init__.py,sha256=eN3wyTPdHTsbW_xDyPXBLDaMA15YuI9qeiy-zeY7ZBQ,260
|
12
|
+
media_agent_mcp/media_selectors/image_selector.py,sha256=143mSxHLLF7uMlOVtnqZlSIFmu7MJkSqyNTJLFhHyls,4726
|
13
|
+
media_agent_mcp/media_selectors/video_selector.py,sha256=HyeZtDbWJVOH95NHNoDnK_r52hS2LOmWGFnXGk_a6CE,6369
|
14
|
+
media_agent_mcp/storage/__init__.py,sha256=eio7ZiSeLjCxICSZwZisiR7wKJfXlT2PV7aDEQKBUQQ,215
|
15
|
+
media_agent_mcp/storage/tos_client.py,sha256=9c3GPmQe2stvxgZzsWYjVqKzVyvluZqYneCXYj-FQ3M,3174
|
16
|
+
media_agent_mcp/video/__init__.py,sha256=4ILnqYaUaYKI4GWOSg2SNZqt10UM1Y-8Q2SVvjoijqY,277
|
17
|
+
media_agent_mcp/video/processor.py,sha256=5ABPyj1IoD2xyIiB8dkEx4ZssPTXKHtuoFjy-dmnFks,11866
|
18
|
+
media_agent_mcp-0.4.0.dist-info/METADATA,sha256=RRSacSquUjyaAonR7PpM0_7Kt_aRKa0oeBA9T1H7P8s,11005
|
19
|
+
media_agent_mcp-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
20
|
+
media_agent_mcp-0.4.0.dist-info/entry_points.txt,sha256=qhOUwR-ORVf9GO7emhhl7Lgd6MISgqbZr8bEuSH_VdA,70
|
21
|
+
media_agent_mcp-0.4.0.dist-info/top_level.txt,sha256=WEa0YfchpTxZgiKn8gdxYgs-dir5HepJaTOrxAGx9nY,16
|
22
|
+
media_agent_mcp-0.4.0.dist-info/RECORD,,
|
@@ -1,21 +0,0 @@
|
|
1
|
-
media_agent_mcp/__init__.py,sha256=4kV5u8kHrsdjpMHDNUhc8h4U6AwOyw1mNptFPd2snrQ,365
|
2
|
-
media_agent_mcp/async_server.py,sha256=vpOMvN804eWz-FKf00Y_H3pE5FTl2C52SeXvFtfDJ8U,10495
|
3
|
-
media_agent_mcp/async_wrapper.py,sha256=bHi0cCKxv6R9oHcNcNq8tV0AyKrTDV47s8BuWetqlIg,8992
|
4
|
-
media_agent_mcp/server.py,sha256=-mTeNcJXIlgByCG2HhaqV6zSbhjrQIEv_ssLN47KAzM,13759
|
5
|
-
media_agent_mcp/ai_models/__init__.py,sha256=WN8JDSJbj2-sNwaQg3MDwmm9mvJTC1mqpWliac3sHoc,427
|
6
|
-
media_agent_mcp/ai_models/seed16.py,sha256=P3KHNF_SfLryJz6qFP7UUtBfw_28ubdrj2lJkt3WsY8,4989
|
7
|
-
media_agent_mcp/ai_models/seedance.py,sha256=fv7hdxlwRtFqMnOG9o7Kx_-k2ihB6VBgN3wCoo-Y-Qs,9024
|
8
|
-
media_agent_mcp/ai_models/seededit.py,sha256=eLOox-8lZudTYe0CpWyONGHC8D12r7nakhkXIXmE7H4,3245
|
9
|
-
media_agent_mcp/ai_models/seedream.py,sha256=lKWMRzV-ZjZ2JB93A3XYUOF7QfzP3zFMQleBtEOkuW8,4467
|
10
|
-
media_agent_mcp/media_selectors/__init__.py,sha256=eN3wyTPdHTsbW_xDyPXBLDaMA15YuI9qeiy-zeY7ZBQ,260
|
11
|
-
media_agent_mcp/media_selectors/image_selector.py,sha256=jVPgk3LiruMK2SJ4gPqCGkRmum2ahObTRbQ7q1sjvhg,4625
|
12
|
-
media_agent_mcp/media_selectors/video_selector.py,sha256=xgTyvuVSBTeZHQGFB6mjLvpYPGTodlHGuGZT3n8D2gA,6268
|
13
|
-
media_agent_mcp/storage/__init__.py,sha256=eio7ZiSeLjCxICSZwZisiR7wKJfXlT2PV7aDEQKBUQQ,215
|
14
|
-
media_agent_mcp/storage/tos_client.py,sha256=9c3GPmQe2stvxgZzsWYjVqKzVyvluZqYneCXYj-FQ3M,3174
|
15
|
-
media_agent_mcp/video/__init__.py,sha256=4ILnqYaUaYKI4GWOSg2SNZqt10UM1Y-8Q2SVvjoijqY,277
|
16
|
-
media_agent_mcp/video/processor.py,sha256=5ABPyj1IoD2xyIiB8dkEx4ZssPTXKHtuoFjy-dmnFks,11866
|
17
|
-
media_agent_mcp-0.3.10.dist-info/METADATA,sha256=F0VfYB3vYpzoj0vk9537QWNBFIsCjfzpGUrvd15QdA8,11007
|
18
|
-
media_agent_mcp-0.3.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
19
|
-
media_agent_mcp-0.3.10.dist-info/entry_points.txt,sha256=qhOUwR-ORVf9GO7emhhl7Lgd6MISgqbZr8bEuSH_VdA,70
|
20
|
-
media_agent_mcp-0.3.10.dist-info/top_level.txt,sha256=WEa0YfchpTxZgiKn8gdxYgs-dir5HepJaTOrxAGx9nY,16
|
21
|
-
media_agent_mcp-0.3.10.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|