ysharma HF Staff commited on
Commit
ada4b72
Β·
verified Β·
1 Parent(s): 6317d02

Create ui_components.py

Browse files
Files changed (1) hide show
  1. ui_components.py +200 -0
ui_components.py ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ UI Components for Universal MCP Client
3
+ """
4
+ import gradio as gr
5
+ from typing import Tuple, List, Dict, Any
6
+
7
+ from config import AppConfig, CUSTOM_CSS
8
+ from chat_handler import ChatHandler
9
+ from server_manager import ServerManager
10
+ from mcp_client import UniversalMCPClient
11
+
12
+ class UIComponents:
13
+ """Manages Gradio UI components and event handlers"""
14
+
15
+ def __init__(self, mcp_client: UniversalMCPClient):
16
+ self.mcp_client = mcp_client
17
+ self.chat_handler = ChatHandler(mcp_client)
18
+ self.server_manager = ServerManager(mcp_client)
19
+
20
+ def create_interface(self) -> gr.Blocks:
21
+ """Create the main Gradio interface"""
22
+ with gr.Blocks(
23
+ title="Universal MCP Client",
24
+ theme=getattr(gr.themes, AppConfig.GRADIO_THEME.title())(),
25
+ fill_height=True,
26
+ css=CUSTOM_CSS
27
+ ) as demo:
28
+
29
+ # Create sidebar
30
+ self._create_sidebar()
31
+
32
+ # Create main chat area
33
+ chatbot = self._create_main_chat_area()
34
+
35
+ # Set up event handlers
36
+ self._setup_event_handlers(chatbot)
37
+
38
+ return demo
39
+
40
+ def _create_sidebar(self):
41
+ """Create the sidebar with server management"""
42
+ with gr.Sidebar():
43
+ gr.Markdown("# Gradio.chat.app")
44
+
45
+ # Collapsible information section
46
+ with gr.Accordion("πŸ“š Guide & Info", open=True):
47
+ gr.Markdown("""
48
+ ## βœ… Quick Start
49
+
50
+ **Native Capabilities:**
51
+ - πŸ‘οΈ **Image Understanding**: Upload & ask "What's in this?"
52
+ - πŸ’¬ **Chat**: All conversation capabilities
53
+ - 🧠 **Analysis**: Code, text, documents
54
+
55
+ **MCP Servers:**
56
+ - 🎨 **Generate**: Images, audio, content
57
+ - ⚑ **Process**: Files via connected servers
58
+ - πŸ”§ **Edit**: Transform existing media
59
+ """)
60
+
61
+ gr.Markdown("""
62
+ ## 🎯 How It Works
63
+
64
+ 1. **Direct Tasks**: Claude handles image analysis instantly
65
+ 2. **Generation**: MCP servers create new content
66
+ 3. **File Processing**: Server-dependent compatibility
67
+
68
+ ## πŸ“ File Support
69
+ - **Images**: PNG, JPG, GIF, WebP
70
+ - **Audio**: MP3, WAV, M4A, FLAC
71
+ - **Video**: MP4, AVI, MOV
72
+ - **Documents**: PDF, TXT, DOCX
73
+ """)
74
+
75
+ # Server status (not in accordion) - make it reactive
76
+ gr.Markdown("## πŸ”§ Server Status")
77
+ self.server_count_display = gr.Markdown(f"**Connected Servers**: {len(self.mcp_client.servers)}")
78
+
79
+ if self.mcp_client.servers:
80
+ server_list = "\n".join([f"β€’ **{name}**" for name in self.mcp_client.servers.keys()])
81
+ self.server_list_display = gr.Markdown(server_list)
82
+ else:
83
+ self.server_list_display = gr.Markdown("*No servers connected*\n\nAdd servers below.")
84
+
85
+ # Server management in accordion
86
+ self._create_server_management_section()
87
+
88
+ def _create_server_management_section(self):
89
+ """Create the server management section in sidebar"""
90
+ with gr.Accordion("βš™οΈ Manage Servers", open=False):
91
+ gr.Markdown("### Add MCP Server")
92
+
93
+ self.server_name = gr.Textbox(
94
+ label="Server Title",
95
+ placeholder="Text to Image Generator"
96
+ )
97
+ self.space_name = gr.Textbox(
98
+ label="HuggingFace Space Name",
99
+ placeholder="ysharma/dalle-3-xl-lora-v2"
100
+ )
101
+
102
+ self.add_server_btn = gr.Button("Add Server", variant="primary")
103
+ self.add_server_output = gr.Textbox(label="Status", interactive=False)
104
+ self.add_server_details = gr.HTML(label="Details")
105
+
106
+ self.status_btn = gr.Button("Refresh Status", variant="secondary")
107
+ self.status_count = gr.Markdown("**Total MCP Servers**: 0")
108
+ self.status_output = gr.HTML()
109
+
110
+ def _create_main_chat_area(self) -> gr.Chatbot:
111
+ """Create the main chat area"""
112
+ with gr.Column(elem_classes="main-content"):
113
+ # Chatbot takes most of the space
114
+ chatbot = gr.Chatbot(
115
+ label="Universal MCP-Powered Multimodal Chatbot",
116
+ show_label=False,
117
+ type="messages",
118
+ scale=1, # Expand to fill available space
119
+ show_copy_button=True,
120
+ avatar_images=None
121
+ )
122
+
123
+ # Input area at bottom - fixed size
124
+ with gr.Column(scale=0, elem_classes="input-area"):
125
+ self.chat_input = gr.MultimodalTextbox(
126
+ interactive=True,
127
+ file_count="multiple",
128
+ placeholder="Enter message or upload files (images, audio, video, documents)...",
129
+ show_label=False,
130
+ sources=["upload", "microphone"],
131
+ file_types=None # Accept all file types
132
+ )
133
+
134
+ return chatbot
135
+
136
+ def _setup_event_handlers(self, chatbot: gr.Chatbot):
137
+ """Set up all event handlers for the interface"""
138
+
139
+ # Chat event handlers
140
+ def submit_message(message, history):
141
+ if message and (message.get("text", "").strip() or message.get("files", [])):
142
+ new_history, cleared_input = self.chat_handler.process_multimodal_message(message, history)
143
+ return new_history, cleared_input
144
+ return history, gr.MultimodalTextbox(value=None, interactive=False)
145
+
146
+ def enable_input():
147
+ return gr.MultimodalTextbox(interactive=True)
148
+
149
+ # Set up the chat flow - using built-in submit functionality
150
+ chat_msg_enter = self.chat_input.submit(
151
+ submit_message,
152
+ inputs=[self.chat_input, chatbot],
153
+ outputs=[chatbot, self.chat_input]
154
+ )
155
+ chat_msg_enter.then(enable_input, None, [self.chat_input])
156
+
157
+ # Server management event handlers
158
+ def update_server_display():
159
+ """Update the server status display in sidebar"""
160
+ server_count = len(self.mcp_client.servers)
161
+ count_text = f"**Connected Servers**: {server_count}"
162
+
163
+ if self.mcp_client.servers:
164
+ server_list = "\n".join([f"β€’ **{name}**" for name in self.mcp_client.servers.keys()])
165
+ return count_text, server_list
166
+ else:
167
+ return count_text, "*No servers connected*\n\nAdd servers below."
168
+
169
+ def handle_add_server(name, space_name):
170
+ """Handle adding a server and update displays"""
171
+ status_msg, details_html = self.server_manager.add_custom_server(name, space_name)
172
+
173
+ # Update sidebar server display
174
+ count_text, list_text = update_server_display()
175
+
176
+ return status_msg, details_html, count_text, list_text, "", "" # Clear inputs
177
+
178
+ def handle_refresh_status():
179
+ """Handle refresh status button"""
180
+ count_text, accordions_html = self.server_manager.get_server_status()
181
+ return count_text, accordions_html
182
+
183
+ # Connect server management events
184
+ self.add_server_btn.click(
185
+ handle_add_server,
186
+ inputs=[self.server_name, self.space_name],
187
+ outputs=[
188
+ self.add_server_output,
189
+ self.add_server_details,
190
+ self.server_count_display,
191
+ self.server_list_display,
192
+ self.server_name,
193
+ self.space_name
194
+ ]
195
+ )
196
+
197
+ self.status_btn.click(
198
+ handle_refresh_status,
199
+ outputs=[self.status_count, self.status_output]
200
+ )