media-agent-mcp 0.1.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/__init__.py +7 -0
- media_agent_mcp/ai_models/__init__.py +17 -0
- media_agent_mcp/ai_models/seed16.py +151 -0
- media_agent_mcp/ai_models/seedance.py +258 -0
- media_agent_mcp/ai_models/seededit.py +94 -0
- media_agent_mcp/ai_models/seedream.py +136 -0
- media_agent_mcp/media_selectors/__init__.py +9 -0
- media_agent_mcp/media_selectors/image_selector.py +119 -0
- media_agent_mcp/media_selectors/video_selector.py +159 -0
- media_agent_mcp/server.py +405 -0
- media_agent_mcp/storage/__init__.py +8 -0
- media_agent_mcp/storage/tos_client.py +98 -0
- media_agent_mcp/video/__init__.py +9 -0
- media_agent_mcp/video/processor.py +337 -0
- media_agent_mcp-0.1.0.dist-info/METADATA +495 -0
- media_agent_mcp-0.1.0.dist-info/RECORD +18 -0
- media_agent_mcp-0.1.0.dist-info/WHEEL +4 -0
- media_agent_mcp-0.1.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
"""AI models module for Media Agent MCP.
|
2
|
+
|
3
|
+
This module provides AI model functionality including image generation,
|
4
|
+
video generation, character maintenance, and vision-language tasks.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .seedream import generate_image
|
8
|
+
from .seedance import generate_video
|
9
|
+
from .seededit import seededit
|
10
|
+
from .seed16 import process_vlm_task
|
11
|
+
|
12
|
+
__all__ = [
|
13
|
+
'generate_image',
|
14
|
+
'generate_video',
|
15
|
+
'seededit',
|
16
|
+
'process_vlm_task'
|
17
|
+
]
|
@@ -0,0 +1,151 @@
|
|
1
|
+
"""Seed1.6 VLM module.
|
2
|
+
|
3
|
+
This module provides functionality for vision-language tasks using the Seed1.6 model.
|
4
|
+
Based on ModelArk Chat API documentation with blocking requests.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import json
|
8
|
+
import logging
|
9
|
+
import os
|
10
|
+
from typing import Dict, Any, List
|
11
|
+
|
12
|
+
import requests
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
16
|
+
|
17
|
+
def process_vlm_task(messages: List[Dict[str, Any]], max_tokens: int = 4096,
|
18
|
+
temperature: float = 0.7, top_p: float = 0.9, is_json: bool = False, **kwargs) -> Dict[str, Any]:
|
19
|
+
"""Process a vision-language task using Seed1.6 model with blocking request.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
messages: List of messages in OpenAI format
|
23
|
+
max_tokens: Maximum tokens to generate
|
24
|
+
temperature: Sampling temperature (0-2)
|
25
|
+
top_p: Nucleus sampling parameter (0-1)
|
26
|
+
**kwargs: Additional parameters
|
27
|
+
|
28
|
+
Returns:
|
29
|
+
JSON response with status, data (response text), and message
|
30
|
+
"""
|
31
|
+
try:
|
32
|
+
# Get API configuration from environment
|
33
|
+
api_key = os.getenv('ARK_API_KEY')
|
34
|
+
vlm_ep = os.getenv('VLM_EP', 'seed-1-6-250615')
|
35
|
+
if not api_key and not vlm_ep:
|
36
|
+
raise ValueError("ARK_API_KEY environment variable must be set")
|
37
|
+
|
38
|
+
# API endpoint for chat completions
|
39
|
+
endpoint = "https://ark.ap-southeast.bytepluses.com/api/v3/chat/completions"
|
40
|
+
|
41
|
+
headers = {
|
42
|
+
'Authorization': f'Bearer {api_key}',
|
43
|
+
'Content-Type': 'application/json'
|
44
|
+
}
|
45
|
+
|
46
|
+
# Prepare request payload according to API documentation
|
47
|
+
payload = {
|
48
|
+
'model': vlm_ep,
|
49
|
+
'messages': messages,
|
50
|
+
'max_tokens': max_tokens,
|
51
|
+
'temperature': temperature,
|
52
|
+
'top_p': top_p,
|
53
|
+
'stream': False # Blocking request
|
54
|
+
}
|
55
|
+
|
56
|
+
if is_json:
|
57
|
+
payload['response_format'] = {'type': 'json_object'}
|
58
|
+
|
59
|
+
logger.info(f"Processing VLM task with Seed1.6: {len(messages)} messages")
|
60
|
+
|
61
|
+
# Make blocking API request
|
62
|
+
response = requests.post(
|
63
|
+
endpoint,
|
64
|
+
headers=headers,
|
65
|
+
json=payload,
|
66
|
+
timeout=120 # Longer timeout for VLM tasks
|
67
|
+
)
|
68
|
+
|
69
|
+
if response.status_code == 200:
|
70
|
+
result = response.json()
|
71
|
+
|
72
|
+
# Extract response text
|
73
|
+
if 'choices' in result and len(result['choices']) > 0:
|
74
|
+
choice = result['choices'][0]
|
75
|
+
if 'message' in choice and 'content' in choice['message']:
|
76
|
+
response_text = choice['message']['content']
|
77
|
+
logger.info(f"VLM task completed successfully")
|
78
|
+
return {
|
79
|
+
"status": "success",
|
80
|
+
"data": {"response": response_text},
|
81
|
+
"message": "VLM task completed successfully"
|
82
|
+
}
|
83
|
+
else:
|
84
|
+
return {
|
85
|
+
"status": "error",
|
86
|
+
"data": None,
|
87
|
+
"message": "No content in response message"
|
88
|
+
}
|
89
|
+
else:
|
90
|
+
return {
|
91
|
+
"status": "error",
|
92
|
+
"data": None,
|
93
|
+
"message": "No choices in response"
|
94
|
+
}
|
95
|
+
else:
|
96
|
+
error_msg = f"API request failed with status {response.status_code}: {response.text}"
|
97
|
+
logger.error(error_msg)
|
98
|
+
return {
|
99
|
+
"status": "error",
|
100
|
+
"data": None,
|
101
|
+
"message": error_msg
|
102
|
+
}
|
103
|
+
|
104
|
+
except requests.exceptions.Timeout:
|
105
|
+
error_msg = "Request timeout - VLM task took too long"
|
106
|
+
logger.error(error_msg)
|
107
|
+
return {
|
108
|
+
"status": "error",
|
109
|
+
"data": None,
|
110
|
+
"message": error_msg
|
111
|
+
}
|
112
|
+
except requests.exceptions.RequestException as e:
|
113
|
+
error_msg = f"Network error: {str(e)}"
|
114
|
+
logger.error(error_msg)
|
115
|
+
return {
|
116
|
+
"status": "error",
|
117
|
+
"data": None,
|
118
|
+
"message": error_msg
|
119
|
+
}
|
120
|
+
except Exception as e:
|
121
|
+
error_msg = f"Unexpected error in Seed1.6 VLM task: {str(e)}"
|
122
|
+
logger.error(error_msg)
|
123
|
+
return {
|
124
|
+
"status": "error",
|
125
|
+
"data": None,
|
126
|
+
"message": error_msg
|
127
|
+
}
|
128
|
+
|
129
|
+
|
130
|
+
if __name__ == '__main__':
|
131
|
+
# Example usage
|
132
|
+
messages = [
|
133
|
+
{
|
134
|
+
"role": "user",
|
135
|
+
"content": [
|
136
|
+
{
|
137
|
+
"type": "text",
|
138
|
+
"text": "Describe the image in detail."
|
139
|
+
},
|
140
|
+
{
|
141
|
+
"type": "image_url",
|
142
|
+
"image_url": {
|
143
|
+
"url": "https://carey.tos-ap-southeast-1.bytepluses.com/Art%20Portrait/Art%20Portrait/Art%20Portrait/Art%20Portrait%20(2).jpg"
|
144
|
+
}
|
145
|
+
}
|
146
|
+
]
|
147
|
+
}
|
148
|
+
]
|
149
|
+
|
150
|
+
response = process_vlm_task(messages)
|
151
|
+
print(response)
|
@@ -0,0 +1,258 @@
|
|
1
|
+
"""Seedance video generation module.
|
2
|
+
|
3
|
+
This module provides functionality for generating videos using the Seedance AI model.
|
4
|
+
Based on ModelArk Video Generation API documentation with async polling.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import json
|
8
|
+
import logging
|
9
|
+
import os
|
10
|
+
import time
|
11
|
+
from typing import Dict, Any
|
12
|
+
|
13
|
+
import requests
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
def generate_video(prompt: str = "", first_frame_image: str = None, last_frame_image: str = None,
|
19
|
+
duration: int = 5, resolution: str = "720p",
|
20
|
+
fps: int = 24, seed: int = -1, **kwargs) -> Dict[str, Any]:
|
21
|
+
"""Generate a video using Seedance model with first/last frame images.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
prompt: Text prompt for video generation (optional for image-to-video)
|
25
|
+
first_frame_image: URL or base64 of the first frame image
|
26
|
+
last_frame_image: URL or base64 of the last frame image (optional)
|
27
|
+
duration: Video duration in seconds (5 or 10)
|
28
|
+
resolution: Video resolution (480p, 720p, 1080p)
|
29
|
+
ratio: Aspect ratio (21:9, 16:9, 4:3, 1:1, 3:4, 9:16, 9:21, adaptive)
|
30
|
+
fps: Frames per second (24)
|
31
|
+
seed: Random seed for reproducibility (-1 for random)
|
32
|
+
**kwargs: Additional parameters
|
33
|
+
|
34
|
+
Returns:
|
35
|
+
JSON response with status, data (video URL), and message
|
36
|
+
"""
|
37
|
+
try:
|
38
|
+
# Get API configuration from environment
|
39
|
+
api_key = os.getenv('ARK_API_KEY')
|
40
|
+
seedance_ep = os.getenv('SEEDANCE_EP', 'seedance-1-0-lite-i2v-250428')
|
41
|
+
if not api_key or not seedance_ep:
|
42
|
+
raise ValueError("ARK_API_KEY environment variable must be set")
|
43
|
+
|
44
|
+
# API endpoint for video generapyttion tasks
|
45
|
+
endpoint = "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks"
|
46
|
+
|
47
|
+
headers = {
|
48
|
+
'Authorization': f'Bearer {api_key}',
|
49
|
+
'Content-Type': 'application/json'
|
50
|
+
}
|
51
|
+
|
52
|
+
# Determine model based on input type
|
53
|
+
model = os.getenv('SEEDANCE_EP', 'seedance-1-0-lite-i2v-250428')
|
54
|
+
|
55
|
+
# Prepare content array for the request
|
56
|
+
content = []
|
57
|
+
|
58
|
+
# Add text content if prompt is provided
|
59
|
+
if prompt:
|
60
|
+
text_content = prompt
|
61
|
+
# Add parameters to the prompt
|
62
|
+
text_content += f" --rs {resolution} --dur {duration} --fps {fps}"
|
63
|
+
if seed != -1:
|
64
|
+
text_content += f" --seed {seed}"
|
65
|
+
|
66
|
+
content.append({
|
67
|
+
"type": "text",
|
68
|
+
"text": text_content
|
69
|
+
})
|
70
|
+
|
71
|
+
# Add first frame image if provided
|
72
|
+
if first_frame_image:
|
73
|
+
content.append({
|
74
|
+
"role": "first_frame",
|
75
|
+
"type": "image_url",
|
76
|
+
"image_url": {
|
77
|
+
"url": first_frame_image
|
78
|
+
}
|
79
|
+
})
|
80
|
+
|
81
|
+
if last_frame_image and first_frame_image:
|
82
|
+
content.append({
|
83
|
+
"role": "last_frame",
|
84
|
+
"type": "image_url",
|
85
|
+
"image_url": {
|
86
|
+
"url": last_frame_image
|
87
|
+
}
|
88
|
+
})
|
89
|
+
|
90
|
+
# Prepare request payload according to API documentation
|
91
|
+
payload = {
|
92
|
+
'model': model,
|
93
|
+
'content': content
|
94
|
+
}
|
95
|
+
|
96
|
+
logger.info(f"Starting video generation with Seedance: {prompt[:100]}...")
|
97
|
+
|
98
|
+
# Make initial API request to start video generation
|
99
|
+
response = requests.post(
|
100
|
+
endpoint,
|
101
|
+
headers=headers,
|
102
|
+
json=payload,
|
103
|
+
timeout=60
|
104
|
+
)
|
105
|
+
|
106
|
+
if response.status_code != 200:
|
107
|
+
error_msg = f"API request failed with status {response.status_code}: {response.text}"
|
108
|
+
logger.error(error_msg)
|
109
|
+
return {
|
110
|
+
"status": "error",
|
111
|
+
"data": None,
|
112
|
+
"message": error_msg
|
113
|
+
}
|
114
|
+
|
115
|
+
result = response.json()
|
116
|
+
|
117
|
+
# Extract task ID for polling
|
118
|
+
if 'id' not in result:
|
119
|
+
return {
|
120
|
+
"status": "error",
|
121
|
+
"data": None,
|
122
|
+
"message": "No task ID in response"
|
123
|
+
}
|
124
|
+
|
125
|
+
task_id = result['id']
|
126
|
+
logger.info(f"Video generation task started with ID: {task_id}")
|
127
|
+
|
128
|
+
# Poll for completion
|
129
|
+
return _poll_video_status(task_id, api_key)
|
130
|
+
|
131
|
+
except requests.exceptions.Timeout:
|
132
|
+
error_msg = "Request timeout - video generation request took too long"
|
133
|
+
logger.error(error_msg)
|
134
|
+
return {
|
135
|
+
"status": "error",
|
136
|
+
"data": None,
|
137
|
+
"message": error_msg
|
138
|
+
}
|
139
|
+
except requests.exceptions.RequestException as e:
|
140
|
+
error_msg = f"Network error: {str(e)}"
|
141
|
+
logger.error(error_msg)
|
142
|
+
return {
|
143
|
+
"status": "error",
|
144
|
+
"data": None,
|
145
|
+
"message": error_msg
|
146
|
+
}
|
147
|
+
except Exception as e:
|
148
|
+
error_msg = f"Unexpected error in Seedance generation: {str(e)}"
|
149
|
+
logger.error(error_msg)
|
150
|
+
return {
|
151
|
+
"status": "error",
|
152
|
+
"data": None,
|
153
|
+
"message": error_msg
|
154
|
+
}
|
155
|
+
|
156
|
+
|
157
|
+
def _poll_video_status(task_id: str, api_key: str, max_wait_time: int = 90) -> Dict[str, Any]:
|
158
|
+
"""Poll video generation status until completion.
|
159
|
+
|
160
|
+
Args:
|
161
|
+
task_id: The task ID to poll
|
162
|
+
api_key: API key for authentication
|
163
|
+
max_wait_time: Maximum time to wait in seconds
|
164
|
+
|
165
|
+
Returns:
|
166
|
+
JSON response with status, data (video URL), and message
|
167
|
+
"""
|
168
|
+
query_endpoint = f"https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks/{task_id}"
|
169
|
+
|
170
|
+
headers = {
|
171
|
+
'Authorization': f'Bearer {api_key}',
|
172
|
+
'Content-Type': 'application/json'
|
173
|
+
}
|
174
|
+
|
175
|
+
start_time = time.time()
|
176
|
+
|
177
|
+
while time.time() - start_time < max_wait_time:
|
178
|
+
try:
|
179
|
+
response = requests.get(query_endpoint, headers=headers, timeout=30)
|
180
|
+
|
181
|
+
if response.status_code != 200:
|
182
|
+
logger.error(f"Status query failed: {response.status_code} - {response.text}")
|
183
|
+
time.sleep(5)
|
184
|
+
continue
|
185
|
+
|
186
|
+
result = response.json()
|
187
|
+
status = result.get('status')
|
188
|
+
|
189
|
+
logger.info(f"Video generation status: {status}")
|
190
|
+
|
191
|
+
if status == 'succeeded':
|
192
|
+
# Extract video URL from response
|
193
|
+
if 'content' in result and 'video_url' in result['content']:
|
194
|
+
video_url = result['content']['video_url']
|
195
|
+
if video_url:
|
196
|
+
logger.info(f"Video generated successfully: {video_url}")
|
197
|
+
return {
|
198
|
+
"status": "success",
|
199
|
+
"data": {"video_url": video_url},
|
200
|
+
"message": "Video generated successfully"
|
201
|
+
}
|
202
|
+
else:
|
203
|
+
return {
|
204
|
+
"status": "error",
|
205
|
+
"data": None,
|
206
|
+
"message": "No video URL in completed response"
|
207
|
+
}
|
208
|
+
else:
|
209
|
+
return {
|
210
|
+
"status": "error",
|
211
|
+
"data": None,
|
212
|
+
"message": "No video content in completed response"
|
213
|
+
}
|
214
|
+
|
215
|
+
elif status == 'failed':
|
216
|
+
error_detail = result.get('error', {}).get('message', 'Unknown error')
|
217
|
+
return {
|
218
|
+
"status": "error",
|
219
|
+
"data": None,
|
220
|
+
"message": f"Video generation failed - {error_detail}"
|
221
|
+
}
|
222
|
+
|
223
|
+
elif status in ['queued', 'running']:
|
224
|
+
# Continue polling
|
225
|
+
time.sleep(5)
|
226
|
+
continue
|
227
|
+
|
228
|
+
else:
|
229
|
+
logger.warning(f"Unknown status: {status}")
|
230
|
+
time.sleep(5)
|
231
|
+
continue
|
232
|
+
|
233
|
+
except requests.exceptions.RequestException as e:
|
234
|
+
logger.error(f"Error polling status: {str(e)}")
|
235
|
+
time.sleep(5)
|
236
|
+
continue
|
237
|
+
except Exception as e:
|
238
|
+
logger.error(f"Unexpected error polling status: {str(e)}")
|
239
|
+
time.sleep(5)
|
240
|
+
continue
|
241
|
+
|
242
|
+
return f"Error: Video generation timed out after {max_wait_time} seconds"
|
243
|
+
|
244
|
+
|
245
|
+
if __name__ == '__main__':
|
246
|
+
# Example usage
|
247
|
+
video_url = generate_video(
|
248
|
+
prompt="the woman slowly moves",
|
249
|
+
first_frame_image="https://carey.tos-ap-southeast-1.bytepluses.com/Art%20Portrait/Art%20Portrait/Art%20Portrait/Art%20Portrait%20(1).jpg",
|
250
|
+
# last_frame_image="https://carey.tos-ap-southeast-1.bytepluses.com/Art%20Portrait/Art%20Portrait/Art%20Portrait/Art%20Portrait%20(2).jpg",
|
251
|
+
duration=5,
|
252
|
+
resolution="720p",
|
253
|
+
ratio="16:9",
|
254
|
+
fps=24,
|
255
|
+
seed=42
|
256
|
+
)
|
257
|
+
|
258
|
+
print(f"Generated video URL: {video_url}")
|
@@ -0,0 +1,94 @@
|
|
1
|
+
import os
|
2
|
+
from typing import Dict, Any
|
3
|
+
from volcengine.visual.VisualService import VisualService
|
4
|
+
|
5
|
+
|
6
|
+
def parse_seededit_response(response) -> Dict[str, Any]:
|
7
|
+
"""
|
8
|
+
Parse the seededit API response and extract the image URL.
|
9
|
+
|
10
|
+
:param response: The API response dictionary
|
11
|
+
:return: JSON response with status, data (image URL), and message
|
12
|
+
"""
|
13
|
+
try:
|
14
|
+
# Handle both possible response formats
|
15
|
+
if 'data' in response and 'image_urls' in response['data']:
|
16
|
+
# Format 1: {'data': {'image_urls': [...]}}
|
17
|
+
image_urls = response['data']['image_urls']
|
18
|
+
elif 'image_urls' in response:
|
19
|
+
# Format 2: {'image_urls': [...]}
|
20
|
+
image_urls = response['image_urls']
|
21
|
+
else:
|
22
|
+
raise ValueError("No image_urls found in response")
|
23
|
+
|
24
|
+
if not image_urls or len(image_urls) == 0:
|
25
|
+
raise ValueError("Empty image_urls list")
|
26
|
+
|
27
|
+
# Get the first URL and clean it
|
28
|
+
url = image_urls[0]
|
29
|
+
# Remove leading/trailing whitespace and backticks
|
30
|
+
url = url.strip().strip('`').strip()
|
31
|
+
|
32
|
+
return {
|
33
|
+
"status": "success",
|
34
|
+
"data": {"image_url": url},
|
35
|
+
"message": "Image URL parsed successfully"
|
36
|
+
}
|
37
|
+
except Exception as e:
|
38
|
+
return {
|
39
|
+
"status": "error",
|
40
|
+
"data": None,
|
41
|
+
"message": f"Failed to parse response: {e}"
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
def seededit(image_url, prompt, charactor_keep=False, return_url=True, scale=1, seed=-1) -> Dict[str, Any]:
|
46
|
+
"""
|
47
|
+
Perform image editing using the VisualService.
|
48
|
+
|
49
|
+
:param image_url: URL of the input image.
|
50
|
+
:param prompt: The editing prompt.
|
51
|
+
:param charactor_keep: Whether to keep the main character in the image.
|
52
|
+
:param return_url: Whether to return image URL or base64 string.
|
53
|
+
:param scale: Text influence scale (0.1-1.0).
|
54
|
+
:param seed: Random seed for reproducibility.
|
55
|
+
:return: JSON response with status, data (image URL), and message.
|
56
|
+
"""
|
57
|
+
try:
|
58
|
+
visual_service = VisualService()
|
59
|
+
|
60
|
+
# call below method if you don't set ak and sk in $HOME/.volc/config
|
61
|
+
ak = os.getenv('VOLC_AK')
|
62
|
+
sk = os.getenv('VOLC_SK')
|
63
|
+
|
64
|
+
if not ak or not sk:
|
65
|
+
return {
|
66
|
+
"status": "error",
|
67
|
+
"data": None,
|
68
|
+
"message": "VOLC_AK and VOLC_SK environment variables must be set"
|
69
|
+
}
|
70
|
+
|
71
|
+
visual_service.set_ak(ak)
|
72
|
+
visual_service.set_sk(sk)
|
73
|
+
|
74
|
+
form = {
|
75
|
+
"req_key": "seed3l_single_ip" if charactor_keep else "seededit_v3.0",
|
76
|
+
"image_urls": [image_url],
|
77
|
+
'prompt': prompt,
|
78
|
+
'return_url': return_url,
|
79
|
+
'scale': scale,
|
80
|
+
'seed': seed,
|
81
|
+
}
|
82
|
+
|
83
|
+
response = visual_service.cv_process(form)
|
84
|
+
return parse_seededit_response(response)
|
85
|
+
except Exception as e:
|
86
|
+
return {
|
87
|
+
"status": "error",
|
88
|
+
"data": None,
|
89
|
+
"message": f"Error in seededit: {str(e)}"
|
90
|
+
}
|
91
|
+
|
92
|
+
|
93
|
+
if __name__ == '__main__':
|
94
|
+
print(seededit('https://carey.tos-ap-southeast-1.bytepluses.com/Art%20Portrait/Art%20Portrait/Art%20Portrait/Art%20Portrait%20(1).jpg', prompt='在和边钓鱼', charactor_keep=False))
|
@@ -0,0 +1,136 @@
|
|
1
|
+
"""Seedream image generation module.
|
2
|
+
|
3
|
+
This module provides functionality for generating images using the Seedream AI model.
|
4
|
+
Based on ModelArk Image Generation API documentation.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import json
|
8
|
+
import logging
|
9
|
+
import os
|
10
|
+
from typing import Dict, Any
|
11
|
+
|
12
|
+
import requests
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
16
|
+
|
17
|
+
def generate_image(prompt: str, size: str = "1024x1024", guidance_scale: float = 2.5,
|
18
|
+
watermark: bool = True, seed: int = -1, **kwargs) -> Dict[str, Any]:
|
19
|
+
"""Generate an image using Seedream model.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
prompt: Text prompt for image generation
|
23
|
+
size: Image size (e.g., "1024x1024", "864x1152", etc.), Must be between [512x512, 2048x2048]
|
24
|
+
guidance_scale: Controls prompt alignment (1-10)
|
25
|
+
watermark: Whether to add watermark
|
26
|
+
seed: Random seed for reproducibility (-1 for random)
|
27
|
+
**kwargs: Additional parameters
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
JSON response with status, data (image URL), and message
|
31
|
+
"""
|
32
|
+
try:
|
33
|
+
# Get API configuration from environment
|
34
|
+
api_key = os.getenv('ARK_API_KEY')
|
35
|
+
seedream_ep = os.getenv('SEEDREAM_EP', 'seedream-3-0-t2i-250415')
|
36
|
+
|
37
|
+
if not api_key or not seedream_ep:
|
38
|
+
raise ValueError("ARK_API_KEY environment variable must be set")
|
39
|
+
|
40
|
+
# API endpoint for image generation
|
41
|
+
endpoint = "https://ark.ap-southeast.bytepluses.com/api/v3/images/generations"
|
42
|
+
|
43
|
+
headers = {
|
44
|
+
'Authorization': f'Bearer {api_key}',
|
45
|
+
'Content-Type': 'application/json'
|
46
|
+
}
|
47
|
+
|
48
|
+
# Prepare request payload according to API documentation
|
49
|
+
payload = {
|
50
|
+
'model': seedream_ep,
|
51
|
+
'prompt': prompt,
|
52
|
+
'response_format': 'url',
|
53
|
+
'size': size,
|
54
|
+
'guidance_scale': guidance_scale,
|
55
|
+
'watermark': watermark
|
56
|
+
}
|
57
|
+
|
58
|
+
# Add seed if specified
|
59
|
+
if seed != -1:
|
60
|
+
payload['seed'] = seed
|
61
|
+
|
62
|
+
logger.info(f"Generating image with Seedream: {prompt[:100]}...")
|
63
|
+
|
64
|
+
# Make API request
|
65
|
+
response = requests.post(
|
66
|
+
endpoint,
|
67
|
+
headers=headers,
|
68
|
+
json=payload,
|
69
|
+
timeout=60
|
70
|
+
)
|
71
|
+
|
72
|
+
if response.status_code == 200:
|
73
|
+
result = response.json()
|
74
|
+
|
75
|
+
# Extract image URL from response
|
76
|
+
if 'data' in result and len(result['data']) > 0:
|
77
|
+
image_url = result['data'][0].get('url')
|
78
|
+
if image_url:
|
79
|
+
logger.info(f"Image generated successfully: {image_url}")
|
80
|
+
return {
|
81
|
+
"status": "success",
|
82
|
+
"data": {"image_url": image_url},
|
83
|
+
"message": "Image generated successfully"
|
84
|
+
}
|
85
|
+
else:
|
86
|
+
return {
|
87
|
+
"status": "error",
|
88
|
+
"data": None,
|
89
|
+
"message": "No image URL in response"
|
90
|
+
}
|
91
|
+
else:
|
92
|
+
return {
|
93
|
+
"status": "error",
|
94
|
+
"data": None,
|
95
|
+
"message": "No image data in response"
|
96
|
+
}
|
97
|
+
else:
|
98
|
+
error_msg = f"API request failed with status {response.status_code}: {response.text}"
|
99
|
+
logger.error(error_msg)
|
100
|
+
return {
|
101
|
+
"status": "error",
|
102
|
+
"data": None,
|
103
|
+
"message": error_msg
|
104
|
+
}
|
105
|
+
|
106
|
+
except requests.exceptions.Timeout:
|
107
|
+
error_msg = "Request timeout - image generation took too long"
|
108
|
+
logger.error(error_msg)
|
109
|
+
return {
|
110
|
+
"status": "error",
|
111
|
+
"data": None,
|
112
|
+
"message": error_msg
|
113
|
+
}
|
114
|
+
except requests.exceptions.RequestException as e:
|
115
|
+
error_msg = f"Network error: {str(e)}"
|
116
|
+
logger.error(error_msg)
|
117
|
+
return {
|
118
|
+
"status": "error",
|
119
|
+
"data": None,
|
120
|
+
"message": error_msg
|
121
|
+
}
|
122
|
+
except Exception as e:
|
123
|
+
error_msg = f"Unexpected error in Seedream generation: {str(e)}"
|
124
|
+
logger.error(error_msg)
|
125
|
+
return {
|
126
|
+
"status": "error",
|
127
|
+
"data": None,
|
128
|
+
"message": error_msg
|
129
|
+
}
|
130
|
+
|
131
|
+
|
132
|
+
if __name__ == "__main__":
|
133
|
+
# Test the function
|
134
|
+
prompt = "A serene landscape with mountains and a lake"
|
135
|
+
image_url = generate_image(prompt)
|
136
|
+
print(image_url)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
"""Selectors module for Media Agent MCP.
|
2
|
+
|
3
|
+
This module provides selection functionality for images and videos.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from .image_selector import select_best_image
|
7
|
+
from .video_selector import select_best_video
|
8
|
+
|
9
|
+
__all__ = ['select_best_image', 'select_best_video']
|