File size: 5,946 Bytes
b5df735
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60b9fce
b5df735
 
 
17dac9a
 
 
 
 
 
 
 
 
 
 
 
 
 
7035546
17dac9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60b9fce
 
 
 
 
 
 
 
 
 
 
 
 
 
17dac9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60b9fce
 
17dac9a
 
 
 
 
 
 
 
 
 
 
 
b5df735
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17dac9a
 
 
 
 
 
 
 
 
 
 
 
 
60b9fce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b5df735
 
17dac9a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# FastAPI + Gradio + FastMCP MCP server main entry point

import modal
from contextlib import asynccontextmanager
from fastapi import FastAPI
from gradio.routes import mount_gradio_app
import os
from dotenv import load_dotenv
import uvicorn
from mcp.server.fastmcp import FastMCP

# Import modules
from .tools import mcp_tools  # Import the module, not get_mcp_server function
from .ui.gradio_ui import create_gradio_interface
from .config.config import is_modal_mode, is_local_mode

# Always import modal config since this module might be imported in modal context
try:
    from .config.modal_config import app, image, volume, cache_dir, secrets
    _modal_available = True
except ImportError:
    _modal_available = False

# ==================== Application Creation Function ====================

def create_app():
    """Create and return Gradio application with MCP tools integrated"""
    
    print("πŸš€ Starting Gradio + FastMCP server")
    
    # Create FastMCP server with new tools
    mcp = FastMCP("Podcast MCP")
    
    # Register tools using the new service architecture
    @mcp.tool(description="Transcribe audio files to text using Whisper model with speaker diarization support")
    async def transcribe_audio_file_tool(
        audio_file_path: str,
        model_size: str = "turbo",
        language: str = None,
        output_format: str = "srt",
        enable_speaker_diarization: bool = False
    ):
        return await mcp_tools.transcribe_audio_file(
            audio_file_path, model_size, language, output_format, enable_speaker_diarization
        )
    
    @mcp.tool(description="Download Apple Podcast audio files")
    async def download_apple_podcast_tool(url: str):
        return await mcp_tools.download_apple_podcast(url)
    
    @mcp.tool(description="Download XiaoYuZhou podcast audio files")
    async def download_xyz_podcast_tool(url: str):
        return await mcp_tools.download_xyz_podcast(url)
    
    @mcp.tool(description="Scan directory for MP3 audio files")
    async def get_mp3_files_tool(directory: str):
        return await mcp_tools.get_mp3_files(directory)
    
    @mcp.tool(description="Get basic file information")
    async def get_file_info_tool(file_path: str):
        return await mcp_tools.get_file_info(file_path)
    
    @mcp.tool(description="Read text file content in segments")
    async def read_text_file_segments_tool(
        file_path: str,
        chunk_size: int = 65536,
        start_position: int = 0
    ):
        return await mcp_tools.read_text_file_segments(file_path, chunk_size, start_position)
    
    # Create Gradio interface
    print("🎨 Creating Gradio interface...")
    gradio_app = create_gradio_interface()
    
    # For HF Spaces, return Gradio app directly
    if os.environ.get("HF_SPACES_MODE") == "1":
        print("πŸ€— HF Spaces mode: returning Gradio app directly")
        print("βœ… Server startup completed")
        print("🎨 Gradio UI: /")
        print(f"πŸ“ Server name: {mcp.name}")
        return gradio_app
    
    # For other environments, create FastAPI wrapper with MCP
    print("πŸ”§ Creating FastAPI wrapper...")
    fastapi_wrapper = FastAPI(
        title="Modal AudioTranscriber MCP",
        description="Gradio UI + FastMCP Tool + Modal Integration AudioTranscriber MCP",
        version="1.0.0",
        lifespan=lambda app: mcp.session_manager.run()
    )
    
    # Get FastMCP's streamable HTTP app
    mcp_app = mcp.streamable_http_app()
    
    # Mount FastMCP application to /api path  
    fastapi_wrapper.mount("/api", mcp_app)
    
    # Use Gradio's standard mounting approach
    final_app = mount_gradio_app(
        app=fastapi_wrapper,
        blocks=gradio_app,
        path="",
        app_kwargs={
            "docs_url": "/docs",
            "redoc_url": "/redoc",
        }
    )
    
    print("βœ… Server startup completed")
    print("🎨 Gradio UI: /")
    print("πŸ”§ MCP Streamable HTTP: /api/mcp")
    print(f"πŸ“ Server name: {mcp.name}")
    
    return final_app

# ==================== Modal Deployment Configuration ====================

# Create a separate Modal app for the Gradio interface
if _modal_available:
    gradio_mcp_app = modal.App(name="gradio-mcp-ui")
    
    @gradio_mcp_app.function(
        image=image,
        cpu=2,  # Adequate CPU for UI operations
        memory=4096,  # 4GB memory for stable UI performance
        max_containers=5,  # Reduced to control resource usage
        min_containers=1,  # Keep minimum containers for faster response
        scaledown_window=600,  # 20 minutes before scaling down
        timeout=1800,  # 30 minutes timeout to prevent preemption
        volumes={cache_dir: volume},
        secrets=secrets,
    )
    @modal.concurrent(max_inputs=100)
    @modal.asgi_app()
    def app_entry():
        """Modal deployment function - create and return complete Gradio + MCP application"""
        return create_app()

# ==================== Main Entry Point ====================

def run_local():
    """Run local server with uvicorn"""
    print("🏠 Starting in local mode")
    
    # Set default environment
    os.environ.setdefault("DEPLOYMENT_MODE", "local")
    
    app = create_app()
    
    # Use port 7860 for HF Spaces compatibility
    port = int(os.environ.get("PORT", 7860))
    
    print(f"🌐 Starting server on port {port}")
    
    # For HF Spaces with Gradio app, launch directly
    if os.environ.get("HF_SPACES_MODE") == "1" and hasattr(app, 'launch'):
        print("πŸ€— Launching Gradio app for HF Spaces")
        app.launch(
            server_name="0.0.0.0",
            server_port=port,
            share=False,
            show_error=True
        )
    else:
        # For other environments, use uvicorn
        uvicorn.run(
            app,
            host="0.0.0.0",
            port=port,
            reload=False
        )

if __name__ == "__main__":
    run_local()