media-agent-mcp 2.6.2__py3-none-any.whl → 2.6.4__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.
@@ -183,33 +183,47 @@ def google_edit(image_urls: List[str], prompt: str) -> Dict[str, Any]:
183
183
 
184
184
  contents = pil_images + [prompt]
185
185
 
186
- # model = genai.GenerativeModel("gemini-1.5-flash-latest")
187
- # response = model.generate_content(contents)
188
186
  client = genai.Client(
189
187
  api_key=api_key,
190
188
  )
191
189
 
192
- response = client.models.generate_content(
193
- model="gemini-2.5-flash-image-preview",
194
- contents=contents
195
- )
190
+ # 最多尝试3次
191
+ max_retries = 3
192
+ for attempt in range(max_retries):
193
+ try:
194
+ response = client.models.generate_content(
195
+ model="gemini-2.5-flash-image-preview",
196
+ contents=contents
197
+ )
196
198
 
197
- image_data = None
198
- if response.candidates and response.candidates[0].content and response.candidates[0].content.parts:
199
- image_parts = [
200
- part.inline_data.data
201
- for part in response.candidates[0].content.parts
202
- if part.inline_data
203
- ]
204
- if image_parts:
205
- image_data = image_parts[0]
199
+ image_data = None
200
+ if response.candidates and response.candidates[0].content and response.candidates[0].content.parts:
201
+ image_parts = [
202
+ part.inline_data.data
203
+ for part in response.candidates[0].content.parts
204
+ if part.inline_data
205
+ ]
206
+ if image_parts:
207
+ image_data = image_parts[0]
206
208
 
207
- if not image_data:
208
- return {
209
- "status": "error",
210
- "data": None,
211
- "message": "Google API response did not contain image data."
212
- }
209
+ # 如果获取到了图片数据,跳出重试循环
210
+ if image_data:
211
+ break
212
+
213
+ # 如果是最后一次尝试且仍然没有图片数据,返回错误
214
+ if attempt == max_retries - 1:
215
+ return {
216
+ "status": "error",
217
+ "data": None,
218
+ "message": f"Google API response did not contain image data after {max_retries} attempts."
219
+ }
220
+
221
+ except Exception as api_error:
222
+ # 如果是最后一次尝试,抛出异常
223
+ if attempt == max_retries - 1:
224
+ raise api_error
225
+ # 否则继续下一次尝试
226
+ continue
213
227
 
214
228
  with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_edited_file:
215
229
  temp_edited_file.write(image_data)
@@ -24,6 +24,7 @@ from typing import List, Optional
24
24
  import json
25
25
  from dotenv import load_dotenv
26
26
  import uvicorn
27
+ import anyio
27
28
  from functools import wraps
28
29
 
29
30
  def async_retry(max_retries=3, delay=2):
@@ -80,6 +81,18 @@ from media_agent_mcp.async_wrapper import (
80
81
  logging.basicConfig(level=logging.INFO)
81
82
  logger = logging.getLogger(__name__)
82
83
 
84
+ # Swallow ClosedResourceError from AnyIO (e.g., SSE client disconnected)
85
+ class IgnoreClosedResourceErrorMiddleware:
86
+ def __init__(self, app):
87
+ self.app = app
88
+
89
+ async def __call__(self, scope, receive, send):
90
+ try:
91
+ await self.app(scope, receive, send)
92
+ except anyio.ClosedResourceError:
93
+ logger.warning("SSE client disconnected (ClosedResourceError). Ignoring.")
94
+ return
95
+
83
96
  # Initialize FastMCP server (will be configured in main function)
84
97
  load_dotenv()
85
98
  mcp = FastMCP("Media-Agent-MCP-Async")
@@ -524,7 +537,7 @@ def main():
524
537
  mcp.settings.port = args.port
525
538
  # Use uvicorn to run SSE app with extended keep-alive timeout (5 minutes)
526
539
  uvicorn.run(
527
- mcp.sse_app(),
540
+ IgnoreClosedResourceErrorMiddleware(mcp.sse_app()),
528
541
  host=args.host,
529
542
  port=args.port,
530
543
  timeout_keep_alive=300
media_agent_mcp/server.py CHANGED
@@ -20,6 +20,7 @@ from typing import Optional, Dict, Any
20
20
  import json
21
21
  from dotenv import load_dotenv
22
22
  import uvicorn
23
+ import anyio
23
24
 
24
25
  from mcp.server.fastmcp import FastMCP
25
26
 
@@ -39,6 +40,18 @@ from media_agent_mcp.media_selectors.video_selector import select_best_video
39
40
  logging.basicConfig(level=logging.INFO)
40
41
  logger = logging.getLogger(__name__)
41
42
 
43
+ # Swallow ClosedResourceError from AnyIO (e.g., SSE client disconnected)
44
+ class IgnoreClosedResourceErrorMiddleware:
45
+ def __init__(self, app):
46
+ self.app = app
47
+
48
+ async def __call__(self, scope, receive, send):
49
+ try:
50
+ await self.app(scope, receive, send)
51
+ except anyio.ClosedResourceError:
52
+ logger.warning("SSE client disconnected (ClosedResourceError). Ignoring.")
53
+ return
54
+
42
55
  # Initialize FastMCP server (will be configured in main function)
43
56
  load_dotenv()
44
57
  mcp = FastMCP("Media-Agent-MCP")
@@ -577,7 +590,7 @@ def main():
577
590
  # Configure and run the server
578
591
  if args.transport == 'sse':
579
592
  # SSE transport
580
- uvicorn.run(mcp.create_sse_app(), host=args.host, port=args.port)
593
+ uvicorn.run(IgnoreClosedResourceErrorMiddleware(mcp.create_sse_app()), host=args.host, port=args.port)
581
594
  else:
582
595
  # STDIO transport (default)
583
596
  mcp.run()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: media-agent-mcp
3
- Version: 2.6.2
3
+ Version: 2.6.4
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
@@ -1,10 +1,10 @@
1
1
  media_agent_mcp/__init__.py,sha256=4kV5u8kHrsdjpMHDNUhc8h4U6AwOyw1mNptFPd2snrQ,365
2
- media_agent_mcp/async_server.py,sha256=a1KqygwC46wEq91_6N6Sk5edJ_95sthu4VBe-mCOcXM,19857
2
+ media_agent_mcp/async_server.py,sha256=rZJXfC9Htx1fk2smyCyxflAdaUV8tILvvviUDE9IsnA,20339
3
3
  media_agent_mcp/async_wrapper.py,sha256=hiiBhhz9WeVDfSBWVh6ovhf5jeP5ZbsieBbz9P-KPn0,15351
4
- media_agent_mcp/server.py,sha256=e8ubU0-R0OnuJy5Gk6jPg8rQXq478O_6f5lNMRMyeQA,19494
4
+ media_agent_mcp/server.py,sha256=hZ_m7HodF_ct_q3FXuCrjE6_tw6rXOim38q2sSdTI9I,19976
5
5
  media_agent_mcp/ai_models/__init__.py,sha256=2kHzTYwjQw89U4QGDq0e2WqJScqDkDNlDaWHGak5JeY,553
6
6
  media_agent_mcp/ai_models/omni_human.py,sha256=s_Ja4gEmHG_bgii1x4SoeV73lz0Zg_3iBRvu36goxVA,4643
7
- media_agent_mcp/ai_models/openaiedit.py,sha256=ZTWG9kfKqmSaHQ8rG9_GvU9IsTD_Eb60VG0RfCJPDk8,9077
7
+ media_agent_mcp/ai_models/openaiedit.py,sha256=uu4d2BgXSrjWRdNPs_SryI9muxO93pItVtEze9nDhjc,9776
8
8
  media_agent_mcp/ai_models/seed16.py,sha256=_rPBfgDASxb2_5-mydus-SLK-6XGy2Cy5lLh5ORBtN8,5078
9
9
  media_agent_mcp/ai_models/seedance.py,sha256=ni7LtXn4jTn5wX2NtcWDMj5Eea8LoP1QLYgwSx_GvBs,9014
10
10
  media_agent_mcp/ai_models/seededit.py,sha256=2f0GiQPqH5IJKsZyW0h5WNA99DX--9oOKiD6vqg8Urk,2091
@@ -44,8 +44,8 @@ media_agent_mcp/video/__init__.py,sha256=tfz22XEeFSeuKa3AggYCE0vCDt4IwXRCKW6avof
44
44
  media_agent_mcp/video/processor.py,sha256=twfqmN5DbVryjDawZUcqTUcnglcBJYpUbAnApqHgD0c,12787
45
45
  media_agent_mcp/video/stack.py,sha256=pyoJiJ9NhU1tjy2l3kARI9sWFoC00Fj97psxYOBi2NU,1736
46
46
  media_agent_mcp/video/subtitle.py,sha256=TlrWVhWJqYTUJpnVz7eccwMAn8ixfrRzRxS6ETMY-DM,16323
47
- media_agent_mcp-2.6.2.dist-info/METADATA,sha256=Vs8JRSrWktTDtsuZlXU0dxmNTcCvrIpBiCu4EEQZ3CM,11310
48
- media_agent_mcp-2.6.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
49
- media_agent_mcp-2.6.2.dist-info/entry_points.txt,sha256=qhOUwR-ORVf9GO7emhhl7Lgd6MISgqbZr8bEuSH_VdA,70
50
- media_agent_mcp-2.6.2.dist-info/top_level.txt,sha256=WEa0YfchpTxZgiKn8gdxYgs-dir5HepJaTOrxAGx9nY,16
51
- media_agent_mcp-2.6.2.dist-info/RECORD,,
47
+ media_agent_mcp-2.6.4.dist-info/METADATA,sha256=rqUYSncUPBBUiTQtMTWEax03GEBSCs5JyLC7ErZ_VAw,11310
48
+ media_agent_mcp-2.6.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
49
+ media_agent_mcp-2.6.4.dist-info/entry_points.txt,sha256=qhOUwR-ORVf9GO7emhhl7Lgd6MISgqbZr8bEuSH_VdA,70
50
+ media_agent_mcp-2.6.4.dist-info/top_level.txt,sha256=WEa0YfchpTxZgiKn8gdxYgs-dir5HepJaTOrxAGx9nY,16
51
+ media_agent_mcp-2.6.4.dist-info/RECORD,,