Spaces:
Running
on
Zero
Running
on
Zero
Commit
·
e45d3a4
1
Parent(s):
5040e2f
Preload Deepseek, add MCP fallbacks, upd audio record widget
Browse files
app.py
CHANGED
|
@@ -48,9 +48,9 @@ try:
|
|
| 48 |
except ImportError:
|
| 49 |
MCP_AVAILABLE = False
|
| 50 |
# Fallback imports if MCP is not available
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
try:
|
| 55 |
from TTS.api import TTS
|
| 56 |
TTS_AVAILABLE = True
|
|
@@ -148,6 +148,12 @@ CSS = """
|
|
| 148 |
display: flex;
|
| 149 |
align-items: center;
|
| 150 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
.feature-badge {
|
| 152 |
display: inline-block;
|
| 153 |
padding: 3px 8px;
|
|
@@ -192,6 +198,7 @@ global_tts_model = None
|
|
| 192 |
|
| 193 |
# MCP client storage
|
| 194 |
global_mcp_client = None
|
|
|
|
| 195 |
# MCP server configuration via environment variables
|
| 196 |
# Example: MCP_SERVER_COMMAND="python" MCP_SERVER_ARGS="-m duckduckgo_mcp_server"
|
| 197 |
# Or: MCP_SERVER_COMMAND="npx" MCP_SERVER_ARGS="-y @modelcontextprotocol/server-duckduckgo"
|
|
@@ -630,7 +637,7 @@ def translate_text(text: str, target_lang: str = "en", source_lang: str = None)
|
|
| 630 |
|
| 631 |
async def search_web_mcp(query: str, max_results: int = 5) -> list:
|
| 632 |
"""Search web using MCP tools"""
|
| 633 |
-
global global_mcp_client
|
| 634 |
|
| 635 |
if not MCP_AVAILABLE:
|
| 636 |
logger.warning("MCP not available, falling back to direct search")
|
|
@@ -653,6 +660,8 @@ async def search_web_mcp(query: str, max_results: int = 5) -> list:
|
|
| 653 |
except Exception as e:
|
| 654 |
logger.error(f"Failed to initialize MCP client: {e}")
|
| 655 |
logger.info("Falling back to direct search. To use MCP, ensure MCP server is installed and configured.")
|
|
|
|
|
|
|
| 656 |
return search_web_fallback(query, max_results)
|
| 657 |
|
| 658 |
# Call MCP search tool
|
|
@@ -759,11 +768,14 @@ async def search_web_mcp(query: str, max_results: int = 5) -> list:
|
|
| 759 |
|
| 760 |
def search_web_fallback(query: str, max_results: int = 5) -> list:
|
| 761 |
"""Fallback web search using DuckDuckGo directly (when MCP is not available)"""
|
| 762 |
-
|
| 763 |
-
|
| 764 |
from ddgs import DDGS
|
| 765 |
import requests
|
| 766 |
from bs4 import BeautifulSoup
|
|
|
|
|
|
|
|
|
|
| 767 |
|
| 768 |
try:
|
| 769 |
with DDGS() as ddgs:
|
|
@@ -1585,34 +1597,61 @@ def create_demo():
|
|
| 1585 |
type="messages"
|
| 1586 |
)
|
| 1587 |
with gr.Row(elem_classes="input-row"):
|
| 1588 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1589 |
mic_button = gr.Audio(
|
| 1590 |
sources=["microphone"],
|
| 1591 |
type="filepath",
|
| 1592 |
label="",
|
| 1593 |
show_label=False,
|
| 1594 |
-
container=False
|
| 1595 |
-
)
|
| 1596 |
-
message_input = gr.Textbox(
|
| 1597 |
-
placeholder="Type your medical question here...",
|
| 1598 |
-
show_label=False,
|
| 1599 |
container=False,
|
| 1600 |
-
|
| 1601 |
-
scale=7
|
| 1602 |
)
|
| 1603 |
submit_button = gr.Button("➤", elem_classes="submit-btn", scale=1)
|
| 1604 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1605 |
# Handle microphone transcription
|
| 1606 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1607 |
if audio is None:
|
| 1608 |
-
return ""
|
| 1609 |
transcribed = transcribe_audio(audio)
|
| 1610 |
-
return transcribed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1611 |
|
| 1612 |
mic_button.stop_recording(
|
| 1613 |
-
fn=
|
| 1614 |
inputs=[mic_button],
|
| 1615 |
-
outputs=[message_input]
|
| 1616 |
)
|
| 1617 |
|
| 1618 |
# TTS component for generating speech from messages
|
|
@@ -1779,11 +1818,18 @@ def create_demo():
|
|
| 1779 |
if __name__ == "__main__":
|
| 1780 |
# Preload models on startup
|
| 1781 |
logger.info("Preloading models on startup...")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1782 |
logger.info("Initializing default medical model (MedSwin SFT)...")
|
| 1783 |
initialize_medical_model(DEFAULT_MEDICAL_MODEL)
|
| 1784 |
logger.info("Preloading Whisper model...")
|
| 1785 |
try:
|
| 1786 |
-
|
| 1787 |
if global_whisper_model is not None:
|
| 1788 |
logger.info("Whisper model preloaded successfully!")
|
| 1789 |
else:
|
|
|
|
| 48 |
except ImportError:
|
| 49 |
MCP_AVAILABLE = False
|
| 50 |
# Fallback imports if MCP is not available
|
| 51 |
+
from ddgs import DDGS
|
| 52 |
+
import requests
|
| 53 |
+
from bs4 import BeautifulSoup
|
| 54 |
try:
|
| 55 |
from TTS.api import TTS
|
| 56 |
TTS_AVAILABLE = True
|
|
|
|
| 148 |
display: flex;
|
| 149 |
align-items: center;
|
| 150 |
}
|
| 151 |
+
.recording-timer {
|
| 152 |
+
font-size: 12px;
|
| 153 |
+
color: #666;
|
| 154 |
+
text-align: center;
|
| 155 |
+
margin-top: 5px;
|
| 156 |
+
}
|
| 157 |
.feature-badge {
|
| 158 |
display: inline-block;
|
| 159 |
padding: 3px 8px;
|
|
|
|
| 198 |
|
| 199 |
# MCP client storage
|
| 200 |
global_mcp_client = None
|
| 201 |
+
global_mcp_context = None # Store the context manager
|
| 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"
|
|
|
|
| 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")
|
|
|
|
| 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
|
|
|
|
| 768 |
|
| 769 |
def search_web_fallback(query: str, max_results: int = 5) -> list:
|
| 770 |
"""Fallback web search using DuckDuckGo directly (when MCP is not available)"""
|
| 771 |
+
# Always import here to ensure availability
|
| 772 |
+
try:
|
| 773 |
from ddgs import DDGS
|
| 774 |
import requests
|
| 775 |
from bs4 import BeautifulSoup
|
| 776 |
+
except ImportError:
|
| 777 |
+
logger.error("Fallback dependencies (ddgs, requests, beautifulsoup4) not available")
|
| 778 |
+
return []
|
| 779 |
|
| 780 |
try:
|
| 781 |
with DDGS() as ddgs:
|
|
|
|
| 1597 |
type="messages"
|
| 1598 |
)
|
| 1599 |
with gr.Row(elem_classes="input-row"):
|
| 1600 |
+
message_input = gr.Textbox(
|
| 1601 |
+
placeholder="Type your medical question here...",
|
| 1602 |
+
show_label=False,
|
| 1603 |
+
container=False,
|
| 1604 |
+
lines=1,
|
| 1605 |
+
scale=10
|
| 1606 |
+
)
|
| 1607 |
mic_button = gr.Audio(
|
| 1608 |
sources=["microphone"],
|
| 1609 |
type="filepath",
|
| 1610 |
label="",
|
| 1611 |
show_label=False,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1612 |
container=False,
|
| 1613 |
+
scale=1
|
|
|
|
| 1614 |
)
|
| 1615 |
submit_button = gr.Button("➤", elem_classes="submit-btn", scale=1)
|
| 1616 |
|
| 1617 |
+
# Timer display for recording (shown below input row)
|
| 1618 |
+
recording_timer = gr.Textbox(
|
| 1619 |
+
value="",
|
| 1620 |
+
label="",
|
| 1621 |
+
show_label=False,
|
| 1622 |
+
interactive=False,
|
| 1623 |
+
visible=False,
|
| 1624 |
+
container=False,
|
| 1625 |
+
elem_classes="recording-timer"
|
| 1626 |
+
)
|
| 1627 |
+
|
| 1628 |
# Handle microphone transcription
|
| 1629 |
+
import time
|
| 1630 |
+
recording_start_time = [None]
|
| 1631 |
+
|
| 1632 |
+
def handle_recording_start():
|
| 1633 |
+
"""Called when recording starts"""
|
| 1634 |
+
recording_start_time[0] = time.time()
|
| 1635 |
+
return gr.update(visible=True, value="Recording... 0s")
|
| 1636 |
+
|
| 1637 |
+
def handle_recording_stop(audio):
|
| 1638 |
+
"""Called when recording stops"""
|
| 1639 |
+
recording_start_time[0] = None
|
| 1640 |
if audio is None:
|
| 1641 |
+
return gr.update(visible=False, value=""), ""
|
| 1642 |
transcribed = transcribe_audio(audio)
|
| 1643 |
+
return gr.update(visible=False, value=""), transcribed
|
| 1644 |
+
|
| 1645 |
+
# Use JavaScript for timer updates (simpler than Gradio Timer)
|
| 1646 |
+
mic_button.start_recording(
|
| 1647 |
+
fn=handle_recording_start,
|
| 1648 |
+
outputs=[recording_timer]
|
| 1649 |
+
)
|
| 1650 |
|
| 1651 |
mic_button.stop_recording(
|
| 1652 |
+
fn=handle_recording_stop,
|
| 1653 |
inputs=[mic_button],
|
| 1654 |
+
outputs=[recording_timer, message_input]
|
| 1655 |
)
|
| 1656 |
|
| 1657 |
# TTS component for generating speech from messages
|
|
|
|
| 1818 |
if __name__ == "__main__":
|
| 1819 |
# Preload models on startup
|
| 1820 |
logger.info("Preloading models on startup...")
|
| 1821 |
+
logger.info("Initializing translation model (DeepSeek-R1)...")
|
| 1822 |
+
try:
|
| 1823 |
+
initialize_translation_model()
|
| 1824 |
+
logger.info("Translation model (DeepSeek-R1) preloaded successfully!")
|
| 1825 |
+
except Exception as e:
|
| 1826 |
+
logger.error(f"Translation model preloading failed: {e}")
|
| 1827 |
+
logger.warning("Translation features may be limited")
|
| 1828 |
logger.info("Initializing default medical model (MedSwin SFT)...")
|
| 1829 |
initialize_medical_model(DEFAULT_MEDICAL_MODEL)
|
| 1830 |
logger.info("Preloading Whisper model...")
|
| 1831 |
try:
|
| 1832 |
+
initialize_whisper_model()
|
| 1833 |
if global_whisper_model is not None:
|
| 1834 |
logger.info("Whisper model preloaded successfully!")
|
| 1835 |
else:
|