Spaces:
Running
on
Zero
Running
on
Zero
Commit
·
6e8bf5a
1
Parent(s):
8d74e9c
Use MCP defaults
Browse files
app.py
CHANGED
|
@@ -197,14 +197,74 @@ global_whisper_model = None
|
|
| 197 |
global_tts_model = None
|
| 198 |
|
| 199 |
# MCP client storage
|
| 200 |
-
|
| 201 |
-
|
|
|
|
| 202 |
# MCP server configuration via environment variables
|
| 203 |
# Example: MCP_SERVER_COMMAND="python" MCP_SERVER_ARGS="-m duckduckgo_mcp_server"
|
| 204 |
# Or: MCP_SERVER_COMMAND="npx" MCP_SERVER_ARGS="-y @modelcontextprotocol/server-duckduckgo"
|
| 205 |
MCP_SERVER_COMMAND = os.environ.get("MCP_SERVER_COMMAND", "python")
|
| 206 |
MCP_SERVER_ARGS = os.environ.get("MCP_SERVER_ARGS", "-m duckduckgo_mcp_server").split() if os.environ.get("MCP_SERVER_ARGS") else ["-m", "duckduckgo_mcp_server"]
|
| 207 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
def initialize_translation_model():
|
| 209 |
"""Initialize DeepSeek-R1 model for translation purposes"""
|
| 210 |
global global_translation_model, global_translation_tokenizer
|
|
@@ -310,18 +370,17 @@ def initialize_tts_model():
|
|
| 310 |
|
| 311 |
async def transcribe_audio_mcp(audio_path: str) -> str:
|
| 312 |
"""Transcribe audio using MCP Whisper tool"""
|
| 313 |
-
global global_mcp_client
|
| 314 |
-
|
| 315 |
if not MCP_AVAILABLE:
|
| 316 |
return ""
|
| 317 |
|
| 318 |
try:
|
| 319 |
-
#
|
| 320 |
-
|
|
|
|
| 321 |
return ""
|
| 322 |
|
| 323 |
# Find Whisper tool
|
| 324 |
-
tools = await
|
| 325 |
whisper_tool = None
|
| 326 |
for tool in tools.tools:
|
| 327 |
if "whisper" in tool.name.lower() or "transcribe" in tool.name.lower() or "speech" in tool.name.lower():
|
|
@@ -330,7 +389,7 @@ async def transcribe_audio_mcp(audio_path: str) -> str:
|
|
| 330 |
break
|
| 331 |
|
| 332 |
if whisper_tool:
|
| 333 |
-
result = await
|
| 334 |
whisper_tool.name,
|
| 335 |
arguments={"audio_path": audio_path, "language": "en"}
|
| 336 |
)
|
|
@@ -406,18 +465,17 @@ def transcribe_audio(audio):
|
|
| 406 |
|
| 407 |
async def generate_speech_mcp(text: str) -> str:
|
| 408 |
"""Generate speech using MCP TTS tool"""
|
| 409 |
-
global global_mcp_client
|
| 410 |
-
|
| 411 |
if not MCP_AVAILABLE:
|
| 412 |
return None
|
| 413 |
|
| 414 |
try:
|
| 415 |
-
#
|
| 416 |
-
|
|
|
|
| 417 |
return None
|
| 418 |
|
| 419 |
# Find TTS tool
|
| 420 |
-
tools = await
|
| 421 |
tts_tool = None
|
| 422 |
for tool in tools.tools:
|
| 423 |
if "tts" in tool.name.lower() or "speech" in tool.name.lower() or "synthesize" in tool.name.lower():
|
|
@@ -426,7 +484,7 @@ async def generate_speech_mcp(text: str) -> str:
|
|
| 426 |
break
|
| 427 |
|
| 428 |
if tts_tool:
|
| 429 |
-
result = await
|
| 430 |
tts_tool.name,
|
| 431 |
arguments={"text": text, "language": "en"}
|
| 432 |
)
|
|
@@ -538,18 +596,17 @@ def detect_language(text: str) -> str:
|
|
| 538 |
|
| 539 |
async def translate_text_mcp(text: str, target_lang: str = "en", source_lang: str = None) -> str:
|
| 540 |
"""Translate text using MCP translation tool"""
|
| 541 |
-
global global_mcp_client
|
| 542 |
-
|
| 543 |
if not MCP_AVAILABLE:
|
| 544 |
return ""
|
| 545 |
|
| 546 |
try:
|
| 547 |
-
#
|
| 548 |
-
|
|
|
|
| 549 |
return ""
|
| 550 |
|
| 551 |
# Find translation tool
|
| 552 |
-
tools = await
|
| 553 |
translate_tool = None
|
| 554 |
for tool in tools.tools:
|
| 555 |
if "translate" in tool.name.lower() or "translation" in tool.name.lower():
|
|
@@ -562,7 +619,7 @@ async def translate_text_mcp(text: str, target_lang: str = "en", source_lang: st
|
|
| 562 |
if source_lang:
|
| 563 |
args["source_language"] = source_lang
|
| 564 |
|
| 565 |
-
result = await
|
| 566 |
translate_tool.name,
|
| 567 |
arguments=args
|
| 568 |
)
|
|
@@ -637,36 +694,20 @@ def translate_text(text: str, target_lang: str = "en", source_lang: str = None)
|
|
| 637 |
|
| 638 |
async def search_web_mcp(query: str, max_results: int = 5) -> list:
|
| 639 |
"""Search web using MCP tools"""
|
| 640 |
-
global global_mcp_client, global_mcp_context
|
| 641 |
-
|
| 642 |
if not MCP_AVAILABLE:
|
| 643 |
logger.warning("MCP not available, falling back to direct search")
|
| 644 |
return search_web_fallback(query, max_results)
|
| 645 |
|
| 646 |
try:
|
| 647 |
-
#
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
server_params = StdioServerParameters(
|
| 653 |
-
command=MCP_SERVER_COMMAND,
|
| 654 |
-
args=MCP_SERVER_ARGS
|
| 655 |
-
)
|
| 656 |
-
try:
|
| 657 |
-
global_mcp_client = await stdio_client(server_params)
|
| 658 |
-
await global_mcp_client.__aenter__()
|
| 659 |
-
logger.info("MCP client initialized successfully")
|
| 660 |
-
except Exception as e:
|
| 661 |
-
logger.error(f"Failed to initialize MCP client: {e}")
|
| 662 |
-
logger.info("Falling back to direct search. To use MCP, ensure MCP server is installed and configured.")
|
| 663 |
-
global_mcp_client = None
|
| 664 |
-
global_mcp_context = None
|
| 665 |
-
return search_web_fallback(query, max_results)
|
| 666 |
|
| 667 |
# Call MCP search tool
|
| 668 |
try:
|
| 669 |
-
tools = await
|
| 670 |
except Exception as e:
|
| 671 |
logger.error(f"Failed to list MCP tools: {e}")
|
| 672 |
return search_web_fallback(query, max_results)
|
|
@@ -681,7 +722,7 @@ async def search_web_mcp(query: str, max_results: int = 5) -> list:
|
|
| 681 |
if search_tool:
|
| 682 |
# Execute search via MCP
|
| 683 |
try:
|
| 684 |
-
result = await
|
| 685 |
search_tool.name,
|
| 686 |
arguments={"query": query, "max_results": max_results}
|
| 687 |
)
|
|
@@ -734,7 +775,7 @@ async def search_web_mcp(query: str, max_results: int = 5) -> list:
|
|
| 734 |
if not item.get('url'):
|
| 735 |
continue
|
| 736 |
try:
|
| 737 |
-
fetch_result = await
|
| 738 |
fetch_tool.name,
|
| 739 |
arguments={"url": item['url']}
|
| 740 |
)
|
|
|
|
| 197 |
global_tts_model = None
|
| 198 |
|
| 199 |
# MCP client storage
|
| 200 |
+
global_mcp_session = None
|
| 201 |
+
global_mcp_stdio_ctx = None # Store stdio context to keep it alive
|
| 202 |
+
global_mcp_lock = threading.Lock() # Lock for thread-safe session access
|
| 203 |
# MCP server configuration via environment variables
|
| 204 |
# Example: MCP_SERVER_COMMAND="python" MCP_SERVER_ARGS="-m duckduckgo_mcp_server"
|
| 205 |
# Or: MCP_SERVER_COMMAND="npx" MCP_SERVER_ARGS="-y @modelcontextprotocol/server-duckduckgo"
|
| 206 |
MCP_SERVER_COMMAND = os.environ.get("MCP_SERVER_COMMAND", "python")
|
| 207 |
MCP_SERVER_ARGS = os.environ.get("MCP_SERVER_ARGS", "-m duckduckgo_mcp_server").split() if os.environ.get("MCP_SERVER_ARGS") else ["-m", "duckduckgo_mcp_server"]
|
| 208 |
|
| 209 |
+
async def get_mcp_session():
|
| 210 |
+
"""Get or create MCP client session with proper context management"""
|
| 211 |
+
global global_mcp_session, global_mcp_stdio_ctx
|
| 212 |
+
|
| 213 |
+
if not MCP_AVAILABLE:
|
| 214 |
+
return None
|
| 215 |
+
|
| 216 |
+
# Check if session exists and is still valid
|
| 217 |
+
if global_mcp_session is not None:
|
| 218 |
+
try:
|
| 219 |
+
# Test if session is still alive by listing tools
|
| 220 |
+
await global_mcp_session.list_tools()
|
| 221 |
+
return global_mcp_session
|
| 222 |
+
except Exception as e:
|
| 223 |
+
logger.debug(f"Existing MCP session invalid, recreating: {e}")
|
| 224 |
+
# Clean up old session
|
| 225 |
+
try:
|
| 226 |
+
if global_mcp_session is not None:
|
| 227 |
+
await global_mcp_session.__aexit__(None, None, None)
|
| 228 |
+
except:
|
| 229 |
+
pass
|
| 230 |
+
try:
|
| 231 |
+
if global_mcp_stdio_ctx is not None:
|
| 232 |
+
await global_mcp_stdio_ctx.__aexit__(None, None, None)
|
| 233 |
+
except:
|
| 234 |
+
pass
|
| 235 |
+
global_mcp_session = None
|
| 236 |
+
global_mcp_stdio_ctx = None
|
| 237 |
+
|
| 238 |
+
# Create new session using correct MCP SDK pattern
|
| 239 |
+
try:
|
| 240 |
+
logger.info(f"Creating MCP client session with command: {MCP_SERVER_COMMAND} {MCP_SERVER_ARGS}")
|
| 241 |
+
server_params = StdioServerParameters(
|
| 242 |
+
command=MCP_SERVER_COMMAND,
|
| 243 |
+
args=MCP_SERVER_ARGS
|
| 244 |
+
)
|
| 245 |
+
|
| 246 |
+
# Correct MCP SDK usage: stdio_client is an async context manager
|
| 247 |
+
# that yields (read, write) streams
|
| 248 |
+
stdio_ctx = stdio_client(server_params)
|
| 249 |
+
read, write = await stdio_ctx.__aenter__()
|
| 250 |
+
|
| 251 |
+
# Create ClientSession from the streams
|
| 252 |
+
session = ClientSession(read, write)
|
| 253 |
+
await session.__aenter__()
|
| 254 |
+
|
| 255 |
+
# Store both the session and stdio context to keep them alive
|
| 256 |
+
global_mcp_session = session
|
| 257 |
+
global_mcp_stdio_ctx = stdio_ctx
|
| 258 |
+
logger.info("MCP client session created successfully")
|
| 259 |
+
return session
|
| 260 |
+
except Exception as e:
|
| 261 |
+
logger.error(f"Failed to create MCP client session: {e}")
|
| 262 |
+
import traceback
|
| 263 |
+
logger.debug(traceback.format_exc())
|
| 264 |
+
global_mcp_session = None
|
| 265 |
+
global_mcp_stdio_ctx = None
|
| 266 |
+
return None
|
| 267 |
+
|
| 268 |
def initialize_translation_model():
|
| 269 |
"""Initialize DeepSeek-R1 model for translation purposes"""
|
| 270 |
global global_translation_model, global_translation_tokenizer
|
|
|
|
| 370 |
|
| 371 |
async def transcribe_audio_mcp(audio_path: str) -> str:
|
| 372 |
"""Transcribe audio using MCP Whisper tool"""
|
|
|
|
|
|
|
| 373 |
if not MCP_AVAILABLE:
|
| 374 |
return ""
|
| 375 |
|
| 376 |
try:
|
| 377 |
+
# Get MCP session
|
| 378 |
+
session = await get_mcp_session()
|
| 379 |
+
if session is None:
|
| 380 |
return ""
|
| 381 |
|
| 382 |
# Find Whisper tool
|
| 383 |
+
tools = await session.list_tools()
|
| 384 |
whisper_tool = None
|
| 385 |
for tool in tools.tools:
|
| 386 |
if "whisper" in tool.name.lower() or "transcribe" in tool.name.lower() or "speech" in tool.name.lower():
|
|
|
|
| 389 |
break
|
| 390 |
|
| 391 |
if whisper_tool:
|
| 392 |
+
result = await session.call_tool(
|
| 393 |
whisper_tool.name,
|
| 394 |
arguments={"audio_path": audio_path, "language": "en"}
|
| 395 |
)
|
|
|
|
| 465 |
|
| 466 |
async def generate_speech_mcp(text: str) -> str:
|
| 467 |
"""Generate speech using MCP TTS tool"""
|
|
|
|
|
|
|
| 468 |
if not MCP_AVAILABLE:
|
| 469 |
return None
|
| 470 |
|
| 471 |
try:
|
| 472 |
+
# Get MCP session
|
| 473 |
+
session = await get_mcp_session()
|
| 474 |
+
if session is None:
|
| 475 |
return None
|
| 476 |
|
| 477 |
# Find TTS tool
|
| 478 |
+
tools = await session.list_tools()
|
| 479 |
tts_tool = None
|
| 480 |
for tool in tools.tools:
|
| 481 |
if "tts" in tool.name.lower() or "speech" in tool.name.lower() or "synthesize" in tool.name.lower():
|
|
|
|
| 484 |
break
|
| 485 |
|
| 486 |
if tts_tool:
|
| 487 |
+
result = await session.call_tool(
|
| 488 |
tts_tool.name,
|
| 489 |
arguments={"text": text, "language": "en"}
|
| 490 |
)
|
|
|
|
| 596 |
|
| 597 |
async def translate_text_mcp(text: str, target_lang: str = "en", source_lang: str = None) -> str:
|
| 598 |
"""Translate text using MCP translation tool"""
|
|
|
|
|
|
|
| 599 |
if not MCP_AVAILABLE:
|
| 600 |
return ""
|
| 601 |
|
| 602 |
try:
|
| 603 |
+
# Get MCP session
|
| 604 |
+
session = await get_mcp_session()
|
| 605 |
+
if session is None:
|
| 606 |
return ""
|
| 607 |
|
| 608 |
# Find translation tool
|
| 609 |
+
tools = await session.list_tools()
|
| 610 |
translate_tool = None
|
| 611 |
for tool in tools.tools:
|
| 612 |
if "translate" in tool.name.lower() or "translation" in tool.name.lower():
|
|
|
|
| 619 |
if source_lang:
|
| 620 |
args["source_language"] = source_lang
|
| 621 |
|
| 622 |
+
result = await session.call_tool(
|
| 623 |
translate_tool.name,
|
| 624 |
arguments=args
|
| 625 |
)
|
|
|
|
| 694 |
|
| 695 |
async def search_web_mcp(query: str, max_results: int = 5) -> list:
|
| 696 |
"""Search web using MCP tools"""
|
|
|
|
|
|
|
| 697 |
if not MCP_AVAILABLE:
|
| 698 |
logger.warning("MCP not available, falling back to direct search")
|
| 699 |
return search_web_fallback(query, max_results)
|
| 700 |
|
| 701 |
try:
|
| 702 |
+
# Get MCP session
|
| 703 |
+
session = await get_mcp_session()
|
| 704 |
+
if session is None:
|
| 705 |
+
logger.warning("Failed to get MCP session, falling back to direct search")
|
| 706 |
+
return search_web_fallback(query, max_results)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 707 |
|
| 708 |
# Call MCP search tool
|
| 709 |
try:
|
| 710 |
+
tools = await session.list_tools()
|
| 711 |
except Exception as e:
|
| 712 |
logger.error(f"Failed to list MCP tools: {e}")
|
| 713 |
return search_web_fallback(query, max_results)
|
|
|
|
| 722 |
if search_tool:
|
| 723 |
# Execute search via MCP
|
| 724 |
try:
|
| 725 |
+
result = await session.call_tool(
|
| 726 |
search_tool.name,
|
| 727 |
arguments={"query": query, "max_results": max_results}
|
| 728 |
)
|
|
|
|
| 775 |
if not item.get('url'):
|
| 776 |
continue
|
| 777 |
try:
|
| 778 |
+
fetch_result = await session.call_tool(
|
| 779 |
fetch_tool.name,
|
| 780 |
arguments={"url": item['url']}
|
| 781 |
)
|