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.
@@ -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 (image URL), and message.
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
- return parse_seededit_response(response)
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",
@@ -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 tenacity import retry, stop_after_attempt, wait_fixed
26
-
27
- def _is_result_error(result):
28
- """Return True if the result is a dictionary with status 'error'."""
29
- if isinstance(result, str):
30
- try:
31
- data = json.loads(result)
32
- return isinstance(data, dict) and data.get('status') == 'error'
33
- except json.JSONDecodeError:
34
- return False
35
- return isinstance(result, dict) and result.get('status') == 'error'
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
- async_video_last_frame_tool,
43
- async_seedream_generate_image_tool,
44
- async_seedance_generate_video_tool,
45
- async_seededit_tool,
46
- async_vlm_vision_task_tool,
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
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
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
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
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
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
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
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
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
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
131
- async def seededit_tool(image_url: str, prompt: str, seed: int = -1,
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 Seededit model.
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, seed, scale, charactor_keep)
148
+ return await async_seededit_tool(image_url, prompt)
147
149
 
148
150
 
149
151
  @mcp.tool()
150
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
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
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
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
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
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
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), retry_if_result=_is_result_error)
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
  """
@@ -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, seed: int = -1,
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, seed: int = -1,
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
- return await _sync_seededit(image_url, prompt, seed, scale, charactor_keep)
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.10
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: tenacity>=8.2.3
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,,