media-agent-mcp 2.6.5__tar.gz → 2.6.7__tar.gz
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-2.6.5 → media_agent_mcp-2.6.7}/PKG-INFO +1 -1
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/pyproject.toml +1 -1
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/async_server.py +71 -1
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/server.py +72 -35
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp.egg-info/PKG-INFO +1 -1
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/README.md +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/setup.cfg +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/__init__.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/ai_models/__init__.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/ai_models/omni_human.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/ai_models/openaiedit.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/ai_models/seed16.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/ai_models/seedance.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/ai_models/seededit.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/ai_models/seedream.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/ai_models/tts.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/async_wrapper.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/audio/combiner.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/audio/speed_controller.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/audio/tts.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/README.md +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/__init__.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/__pycache__/__init__.cpython-312.pyc +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/__pycache__/app.cpython-312.pyc +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/__pycache__/routes_media.cpython-312.pyc +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/__pycache__/routes_omni.cpython-312.pyc +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/__pycache__/routes_subtitles.cpython-312.pyc +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/__pycache__/utils.cpython-312.pyc +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/app.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/fonts/en/EduNSWACTCursive-VariableFont_wght.ttf +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/fonts/en/MozillaText-VariableFont_wght.ttf +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/fonts/en/Roboto_Condensed-Regular.ttf +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/fonts/zh/MaShanZheng-Regular.ttf +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/fonts/zh/NotoSerifSC-VariableFont_wght.ttf +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/fonts/zh/ZCOOLXiaoWei-Regular.ttf +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/pyproject.toml +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/routes_media.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/routes_subtitles.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/utils.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/be/uv.lock +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/install_tools/__init__.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/install_tools/installer.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/media_selectors/__init__.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/media_selectors/image_selector.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/media_selectors/video_selector.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/storage/__init__.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/storage/tos_client.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/video/__init__.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/video/processor.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/video/stack.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/video/subtitle.py +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp.egg-info/SOURCES.txt +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp.egg-info/dependency_links.txt +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp.egg-info/entry_points.txt +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp.egg-info/requires.txt +0 -0
- {media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp.egg-info/top_level.txt +0 -0
@@ -26,6 +26,10 @@ from dotenv import load_dotenv
|
|
26
26
|
import uvicorn
|
27
27
|
import anyio
|
28
28
|
from functools import wraps
|
29
|
+
import os
|
30
|
+
import sys
|
31
|
+
import signal
|
32
|
+
import subprocess
|
29
33
|
|
30
34
|
def async_retry(max_retries=3, delay=2):
|
31
35
|
def decorator(func):
|
@@ -132,6 +136,72 @@ class ReconnectableSSEMiddleware:
|
|
132
136
|
# 不抛出异常,允许客户端重连
|
133
137
|
return
|
134
138
|
|
139
|
+
# 在出现错误时重启应用的中间件
|
140
|
+
class RestartOnErrorMiddleware:
|
141
|
+
def __init__(self, app):
|
142
|
+
self.app = app
|
143
|
+
self.restart_cooldown = 5 # 重启冷却时间(秒)
|
144
|
+
self.script_path = os.path.abspath(sys.argv[0])
|
145
|
+
self.args = sys.argv[1:]
|
146
|
+
|
147
|
+
async def __call__(self, scope, receive, send):
|
148
|
+
try:
|
149
|
+
await self.app(scope, receive, send)
|
150
|
+
except anyio.ClosedResourceError:
|
151
|
+
logger.warning("检测到 ClosedResourceError,准备重启应用...")
|
152
|
+
# 等待一段时间,确保日志输出
|
153
|
+
await asyncio.sleep(1)
|
154
|
+
|
155
|
+
# 启动新进程,使用不同的端口避免冲突
|
156
|
+
# 解析当前命令行参数以获取当前端口
|
157
|
+
temp_parser = argparse.ArgumentParser()
|
158
|
+
temp_parser.add_argument('--port', type=int, default=8000)
|
159
|
+
temp_parser.add_argument('--host', type=str, default='127.0.0.1')
|
160
|
+
temp_parser.add_argument('--transport', type=str, default='stdio')
|
161
|
+
# 添加其他可能的参数,避免解析错误
|
162
|
+
temp_parser.add_argument('--run-be', action='store_true')
|
163
|
+
temp_parser.add_argument('--be-host', type=str, default='0.0.0.0')
|
164
|
+
temp_parser.add_argument('--be-port', type=int, default=5000)
|
165
|
+
temp_parser.add_argument('--version', action='store_true')
|
166
|
+
|
167
|
+
# 忽略未知参数,避免解析错误
|
168
|
+
known_args, _ = temp_parser.parse_known_args(self.args)
|
169
|
+
|
170
|
+
# 计算新端口,当前端口+1
|
171
|
+
new_port = known_args.port + 1
|
172
|
+
logger.info(f"将使用新端口 {new_port} 启动新进程")
|
173
|
+
|
174
|
+
# 准备新的命令行参数
|
175
|
+
new_args = self.args.copy()
|
176
|
+
|
177
|
+
# 如果命令行参数中有端口参数,则替换为新端口
|
178
|
+
if '--port' in new_args:
|
179
|
+
port_index = new_args.index('--port') + 1
|
180
|
+
if port_index < len(new_args):
|
181
|
+
new_args[port_index] = str(new_port)
|
182
|
+
else:
|
183
|
+
new_args.extend(['--port', str(new_port)])
|
184
|
+
|
185
|
+
logger.info(f"启动新进程: {self.script_path} {' '.join(new_args)}")
|
186
|
+
new_process = subprocess.Popen([sys.executable, self.script_path] + new_args)
|
187
|
+
|
188
|
+
# 等待确认新进程已启动
|
189
|
+
logger.info(f"等待确认新进程已启动...")
|
190
|
+
await asyncio.sleep(3)
|
191
|
+
|
192
|
+
# 检查新进程是否成功启动
|
193
|
+
if new_process.poll() is None: # None表示进程仍在运行
|
194
|
+
logger.info(f"新进程成功启动,将在 {self.restart_cooldown} 秒后终止当前进程...")
|
195
|
+
await asyncio.sleep(self.restart_cooldown)
|
196
|
+
|
197
|
+
# 终止当前进程
|
198
|
+
logger.info("终止当前进程")
|
199
|
+
sys.exit(0)
|
200
|
+
else:
|
201
|
+
logger.error(f"新进程启动失败,退出码: {new_process.returncode},当前进程将继续运行")
|
202
|
+
return
|
203
|
+
return
|
204
|
+
|
135
205
|
# Initialize FastMCP server (will be configured in main function)
|
136
206
|
load_dotenv()
|
137
207
|
mcp = FastMCP("Media-Agent-MCP-Async")
|
@@ -576,7 +646,7 @@ def main():
|
|
576
646
|
mcp.settings.port = args.port
|
577
647
|
# Use uvicorn to run SSE app with extended keep-alive timeout (5 minutes)
|
578
648
|
uvicorn.run(
|
579
|
-
|
649
|
+
RestartOnErrorMiddleware(mcp.sse_app()),
|
580
650
|
host=args.host,
|
581
651
|
port=args.port,
|
582
652
|
timeout_keep_alive=300
|
@@ -22,6 +22,11 @@ from dotenv import load_dotenv
|
|
22
22
|
import uvicorn
|
23
23
|
import anyio
|
24
24
|
import uuid
|
25
|
+
import os
|
26
|
+
import sys
|
27
|
+
import signal
|
28
|
+
import subprocess
|
29
|
+
import asyncio
|
25
30
|
|
26
31
|
from mcp.server.fastmcp import FastMCP
|
27
32
|
|
@@ -57,46 +62,78 @@ class IgnoreClosedResourceErrorMiddleware:
|
|
57
62
|
class ReconnectableSSEMiddleware:
|
58
63
|
def __init__(self, app):
|
59
64
|
self.app = app
|
60
|
-
self.connections = {}
|
65
|
+
self.connections = {} # 存储活跃连接
|
61
66
|
|
62
67
|
async def __call__(self, scope, receive, send):
|
63
|
-
#
|
64
|
-
connection_id = str(
|
68
|
+
# 为每个连接生成唯一ID
|
69
|
+
connection_id = scope.get('client', ('unknown', 0))[0] + ':' + str(scope.get('client', ('unknown', 0))[1])
|
65
70
|
|
66
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
71
|
+
# 包装send函数以跟踪连接状态
|
72
|
+
original_send = send
|
73
|
+
|
74
|
+
async def wrapped_send(message):
|
75
|
+
if message.get('type') == 'http.response.start':
|
76
|
+
# 记录新连接
|
77
|
+
self.connections[connection_id] = {'active': True}
|
78
|
+
logger.info(f"New SSE connection established: {connection_id}")
|
79
|
+
elif message.get('type') == 'http.response.body' and message.get('more_body', False) is False:
|
80
|
+
# 连接结束
|
81
|
+
if connection_id in self.connections:
|
82
|
+
self.connections[connection_id]['active'] = False
|
83
|
+
logger.info(f"SSE connection closed normally: {connection_id}")
|
76
84
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
85
|
+
# 调用原始send
|
86
|
+
await original_send(message)
|
87
|
+
|
88
|
+
try:
|
89
|
+
# 使用包装后的send函数
|
90
|
+
await self.app(scope, receive, wrapped_send)
|
91
|
+
except anyio.ClosedResourceError:
|
92
|
+
# 客户端断开连接
|
93
|
+
if connection_id in self.connections:
|
94
|
+
self.connections[connection_id]['active'] = False
|
83
95
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
# For non-HTTP connections, just pass through
|
96
|
+
logger.warning(f"SSE client disconnected (ClosedResourceError): {connection_id}. Client can reconnect.")
|
97
|
+
# 不抛出异常,允许客户端重连
|
98
|
+
return
|
99
|
+
|
100
|
+
# 在出现错误时重启应用的中间件
|
101
|
+
class RestartOnErrorMiddleware:
|
102
|
+
def __init__(self, app):
|
103
|
+
self.app = app
|
104
|
+
self.restart_cooldown = 5 # 重启冷却时间(秒)
|
105
|
+
self.script_path = os.path.abspath(sys.argv[0])
|
106
|
+
self.args = sys.argv[1:]
|
107
|
+
|
108
|
+
async def __call__(self, scope, receive, send):
|
109
|
+
try:
|
99
110
|
await self.app(scope, receive, send)
|
111
|
+
except anyio.ClosedResourceError:
|
112
|
+
logger.warning("检测到 ClosedResourceError,准备重启应用...")
|
113
|
+
# 等待一段时间,确保日志输出
|
114
|
+
await asyncio.sleep(1)
|
115
|
+
|
116
|
+
# 启动新进程
|
117
|
+
logger.info(f"启动新进程: {self.script_path} {' '.join(self.args)}")
|
118
|
+
subprocess.Popen([sys.executable, self.script_path] + self.args)
|
119
|
+
|
120
|
+
# 等待冷却时间
|
121
|
+
logger.info(f"等待 {self.restart_cooldown} 秒后终止当前进程...")
|
122
|
+
await asyncio.sleep(self.restart_cooldown)
|
123
|
+
|
124
|
+
# 终止当前进程
|
125
|
+
logger.info("终止当前进程")
|
126
|
+
os.kill(os.getpid(), signal.SIGTERM)
|
127
|
+
return
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
|
135
|
+
|
136
|
+
return
|
100
137
|
|
101
138
|
# Initialize FastMCP server (will be configured in main function)
|
102
139
|
load_dotenv()
|
@@ -636,7 +673,7 @@ def main():
|
|
636
673
|
# Configure and run the server
|
637
674
|
if args.transport == 'sse':
|
638
675
|
# SSE transport
|
639
|
-
uvicorn.run(
|
676
|
+
uvicorn.run(RestartOnErrorMiddleware(mcp.create_sse_app()), host=args.host, port=args.port)
|
640
677
|
else:
|
641
678
|
# STDIO transport (default)
|
642
679
|
mcp.run()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/audio/speed_controller.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/install_tools/__init__.py
RENAMED
File without changes
|
{media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/install_tools/installer.py
RENAMED
File without changes
|
{media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp/media_selectors/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp.egg-info/dependency_links.txt
RENAMED
File without changes
|
{media_agent_mcp-2.6.5 → media_agent_mcp-2.6.7}/src/media_agent_mcp.egg-info/entry_points.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|