Chris4K commited on
Commit
92a2140
Β·
verified Β·
1 Parent(s): 8fdf1e1

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +210 -0
app.py ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import json
3
+ import gradio as gr
4
+ from mcp import ClientSession
5
+ from mcp.client.sse import sse_client
6
+ from contextlib import AsyncExitStack
7
+
8
+ loop = asyncio.new_event_loop()
9
+ asyncio.set_event_loop(loop)
10
+
11
+ class SimpleMCPClient:
12
+ def __init__(self):
13
+ self.session = None
14
+ self.connected = False
15
+ self.tools = []
16
+ self.exit_stack = None
17
+ self.server_url = "https://chris4k-weather.hf.space/gradio_api/mcp/sse"
18
+
19
+ def connect(self) -> str:
20
+ """Connect to the hardcoded MCP server"""
21
+ return loop.run_until_complete(self._connect())
22
+
23
+ async def _connect(self) -> str:
24
+ try:
25
+ # Clean up previous connection
26
+ if self.exit_stack:
27
+ await self.exit_stack.aclose()
28
+
29
+ self.exit_stack = AsyncExitStack()
30
+
31
+ # Connect to SSE MCP server
32
+ sse_transport = await self.exit_stack.enter_async_context(
33
+ sse_client(self.server_url)
34
+ )
35
+ read_stream, write_callable = sse_transport
36
+
37
+ self.session = await self.exit_stack.enter_async_context(
38
+ ClientSession(read_stream, write_callable)
39
+ )
40
+ await self.session.initialize()
41
+
42
+ # Get available tools
43
+ response = await self.session.list_tools()
44
+ self.tools = response.tools
45
+
46
+ self.connected = True
47
+ tool_names = [tool.name for tool in self.tools]
48
+ return f"βœ… Connected to weather server!\nAvailable tools: {', '.join(tool_names)}"
49
+
50
+ except Exception as e:
51
+ self.connected = False
52
+ return f"❌ Connection failed: {str(e)}"
53
+
54
+ def get_weather(self, location: str) -> str:
55
+ """Get weather for a location (city, country format)"""
56
+ if not self.connected:
57
+ return "❌ Not connected to server. Click Connect first."
58
+
59
+ if not location.strip():
60
+ return "❌ Please enter a location (e.g., 'Berlin, Germany')"
61
+
62
+ return loop.run_until_complete(self._get_weather(location))
63
+
64
+ async def _get_weather(self, location: str) -> str:
65
+ try:
66
+ # Parse location
67
+ if ',' in location:
68
+ city, country = [part.strip() for part in location.split(',', 1)]
69
+ else:
70
+ city = location.strip()
71
+ country = ""
72
+
73
+ # Find the weather tool
74
+ weather_tool = next((tool for tool in self.tools if 'weather' in tool.name.lower()), None)
75
+ if not weather_tool:
76
+ return "❌ Weather tool not found on server"
77
+
78
+ # Call the tool
79
+ params = {"city": city, "country": country}
80
+ result = await self.session.call_tool(weather_tool.name, params)
81
+
82
+ # Extract content properly
83
+ content_text = ""
84
+ if hasattr(result, 'content') and result.content:
85
+ if isinstance(result.content, list):
86
+ for content_item in result.content:
87
+ if hasattr(content_item, 'text'):
88
+ content_text += content_item.text
89
+ elif hasattr(content_item, 'content'):
90
+ content_text += str(content_item.content)
91
+ else:
92
+ content_text += str(content_item)
93
+ elif hasattr(result.content, 'text'):
94
+ content_text = result.content.text
95
+ else:
96
+ content_text = str(result.content)
97
+
98
+ if not content_text:
99
+ return "❌ No content received from server"
100
+
101
+ try:
102
+ # Try to parse as JSON
103
+ parsed = json.loads(content_text)
104
+ if isinstance(parsed, dict):
105
+ if 'error' in parsed:
106
+ return f"❌ Error: {parsed['error']}"
107
+
108
+ # Format weather data nicely
109
+ if 'current_weather' in parsed:
110
+ weather = parsed['current_weather']
111
+ formatted = f"🌍 **{parsed.get('location', 'Unknown')}**\n\n"
112
+ formatted += f"🌑️ Temperature: {weather.get('temperature_celsius', 'N/A')}°C\n"
113
+ formatted += f"🌀️ Conditions: {weather.get('weather_description', 'N/A')}\n"
114
+ formatted += f"πŸ’¨ Wind: {weather.get('wind_speed_kmh', 'N/A')} km/h\n"
115
+ formatted += f"πŸ’§ Humidity: {weather.get('humidity_percent', 'N/A')}%\n"
116
+ return formatted
117
+ elif 'temperature (Β°C)' in parsed:
118
+ # Handle the original format from your server
119
+ formatted = f"🌍 **{parsed.get('location', 'Unknown')}**\n\n"
120
+ formatted += f"🌑️ Temperature: {parsed.get('temperature (°C)', 'N/A')}°C\n"
121
+ formatted += f"🌀️ Weather Code: {parsed.get('weather_code', 'N/A')}\n"
122
+ formatted += f"πŸ• Timezone: {parsed.get('timezone', 'N/A')}\n"
123
+ formatted += f"πŸ•’ Local Time: {parsed.get('local_time', 'N/A')}\n"
124
+ return formatted
125
+ else:
126
+ return f"βœ… Weather data:\n```json\n{json.dumps(parsed, indent=2)}\n```"
127
+
128
+ except json.JSONDecodeError:
129
+ # If not JSON, return as text
130
+ return f"βœ… Weather data:\n```\n{content_text}\n```"
131
+
132
+ return f"βœ… Raw result:\n{content_text}"
133
+
134
+ except Exception as e:
135
+ return f"❌ Failed to get weather: {str(e)}"
136
+
137
+ # Global client
138
+ client = SimpleMCPClient()
139
+
140
+ def create_interface():
141
+ with gr.Blocks(title="Weather MCP Test", theme=gr.themes.Soft()) as demo:
142
+ gr.Markdown("# 🌀️ Weather MCP Test Client")
143
+ gr.Markdown("Simple client to test the weather MCP server")
144
+
145
+ # Connection
146
+ with gr.Row():
147
+ connect_btn = gr.Button("πŸ”Œ Connect to Weather Server", variant="primary")
148
+ status = gr.Textbox(
149
+ label="Status",
150
+ value="Click Connect to start",
151
+ interactive=False,
152
+ scale=2
153
+ )
154
+
155
+ # Weather query
156
+ with gr.Group():
157
+ gr.Markdown("### Get Weather")
158
+ with gr.Row():
159
+ location_input = gr.Textbox(
160
+ label="Location",
161
+ placeholder="e.g., Berlin, Germany",
162
+ value="Berlin, Germany",
163
+ scale=3
164
+ )
165
+ weather_btn = gr.Button("🌑️ Get Weather", scale=1)
166
+
167
+ weather_result = gr.Textbox(
168
+ label="Weather Result",
169
+ interactive=False,
170
+ lines=8,
171
+ placeholder="Weather information will appear here..."
172
+ )
173
+
174
+ # Examples
175
+ with gr.Group():
176
+ gr.Markdown("### πŸ“ Examples")
177
+ examples = gr.Examples(
178
+ examples=[
179
+ ["Berlin, Germany"],
180
+ ["Tokyo, Japan"],
181
+ ["New York, USA"],
182
+ ["London, UK"],
183
+ ["Sydney, Australia"]
184
+ ],
185
+ inputs=[location_input]
186
+ )
187
+
188
+ # Event handlers
189
+ connect_btn.click(
190
+ client.connect,
191
+ outputs=[status]
192
+ )
193
+
194
+ weather_btn.click(
195
+ client.get_weather,
196
+ inputs=[location_input],
197
+ outputs=[weather_result]
198
+ )
199
+
200
+ location_input.submit(
201
+ client.get_weather,
202
+ inputs=[location_input],
203
+ outputs=[weather_result]
204
+ )
205
+
206
+ return demo
207
+
208
+ if __name__ == "__main__":
209
+ interface = create_interface()
210
+ interface.launch(debug=True, share=True, mcp_server=True)