cwadayi commited on
Commit
1c9802a
·
verified ·
1 Parent(s): baef405

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +32 -55
app.py CHANGED
@@ -13,8 +13,7 @@ import cartopy.crs as ccrs
13
  import cartopy.feature as cfeature
14
  import base64
15
  import io
16
- from datetime import datetime
17
- from typing import Any, Dict, List, Optional, Tuple
18
  import gradio as gr
19
  import logging
20
 
@@ -160,6 +159,7 @@ class EarthquakeDataService:
160
  image_base64 = base64.b64encode(buffer.getvalue()).decode()
161
  result["map_image_base64"] = image_base64
162
  buffer.close()
 
163
 
164
  return result
165
 
@@ -282,7 +282,7 @@ class EarthquakeMCPServer:
282
  "capabilities": {"tools": {}},
283
  "serverInfo": {
284
  "name": "earthquake-data-server",
285
- "version": "1.1.0"
286
  }
287
  }
288
  }
@@ -305,11 +305,9 @@ class EarthquakeMCPServer:
305
 
306
  if tool_name == "query_earthquakes":
307
  result = await self.data_service.query_earthquakes_data(**arguments)
308
- # Remove dataframe for JSON serialization
309
  result.pop("dataframe", None)
310
  elif tool_name == "create_earthquake_map":
311
  result = await self.data_service.create_earthquake_map(**arguments)
312
- # Remove figure for JSON serialization
313
  result.pop("figure", None)
314
  elif tool_name == "get_earthquake_stats":
315
  result = await self.data_service.get_earthquake_stats(**arguments)
@@ -341,7 +339,7 @@ class EarthquakeMCPServer:
341
  }
342
 
343
  except Exception as e:
344
- logger.error(f"Error handling MCP request: {e}")
345
  return {
346
  "jsonrpc": "2.0",
347
  "id": request.get("id", 0),
@@ -349,45 +347,39 @@ class EarthquakeMCPServer:
349
  }
350
 
351
 
352
- # Global data service instance
353
  data_service = EarthquakeDataService()
354
  mcp_server = EarthquakeMCPServer(data_service)
355
 
356
  # --- Gradio Interface Functions ---
 
357
  async def fetch_and_plot_data(
358
  start_date: str, end_date: str, minimum_magnitude: float
359
  ) -> Tuple[pd.DataFrame, Any]:
360
- """Gradio interface function for fetching and plotting data."""
361
  try:
362
- # Create map which also queries the data internally
363
- map_result = await data_service.create_earthquake_map(
364
  start_date=start_date,
365
  end_date=end_date,
366
  minimum_magnitude=minimum_magnitude
367
  )
368
 
369
- # Query data again to get the dataframe for the table
370
- query_result = await data_service.query_earthquakes_data(
 
 
 
 
371
  start_date=start_date,
372
  end_date=end_date,
373
  minimum_magnitude=minimum_magnitude
374
  )
375
 
376
- df = query_result.get("dataframe", pd.DataFrame())
377
  figure = map_result.get("figure")
378
-
379
  return df, figure
380
 
381
  except Exception as e:
382
- logger.error(f"Error in fetch_and_plot_data: {e}")
383
- return pd.DataFrame({"Error": [str(e)]}), None
384
-
385
- def gradio_fetch_and_plot_data(*args):
386
- """Synchronous wrapper for Gradio."""
387
- try:
388
- return asyncio.run(fetch_and_plot_data(*args))
389
- except Exception as e:
390
- logger.error(f"Error running async fetch_and_plot_data: {e}")
391
  return pd.DataFrame({"Error": [str(e)]}), None
392
 
393
 
@@ -397,22 +389,22 @@ async def handle_mcp_request_gradio(request_json: str) -> str:
397
  request = json.loads(request_json)
398
  response = await mcp_server.handle_mcp_request(request)
399
  return json.dumps(response, indent=2, ensure_ascii=False)
400
- except Exception as e:
 
401
  error_response = {
402
  "jsonrpc": "2.0",
403
  "id": None,
404
- "error": {"code": -32700, "message": f"Parse error: {str(e)}"}
405
  }
406
  return json.dumps(error_response, indent=2)
407
-
408
- def gradio_handle_mcp_request(request_json: str) -> str:
409
- """Synchronous wrapper for MCP requests in Gradio."""
410
- try:
411
- return asyncio.run(handle_mcp_request_gradio(request_json))
412
  except Exception as e:
413
- logger.error(f"Error running async handle_mcp_request_gradio: {e}")
414
- return json.dumps({"error": str(e)})
415
-
 
 
 
 
416
 
417
  # --- Gradio Interface ---
418
  with gr.Blocks(title="Earthquake Data MCP Server", theme=gr.themes.Soft()) as app:
@@ -442,8 +434,9 @@ with gr.Blocks(title="Earthquake Data MCP Server", theme=gr.themes.Soft()) as ap
442
  with gr.Column(scale=3):
443
  output_df = gr.DataFrame(label="Filtered Results")
444
 
 
445
  filter_button.click(
446
- fn=gradio_fetch_and_plot_data,
447
  inputs=[
448
  start_date_input, end_date_input, minimum_magnitude_input
449
  ],
@@ -453,11 +446,7 @@ with gr.Blocks(title="Earthquake Data MCP Server", theme=gr.themes.Soft()) as ap
453
  # MCP Interface Tab
454
  with gr.TabItem("🔌 MCP Interface"):
455
  gr.Markdown("### Model Context Protocol (MCP) Interface")
456
- gr.Markdown("""
457
- This tab allows you to interact with the MCP server directly. Send JSON-RPC requests to test the MCP functionality.
458
-
459
- **Available Tools:** `query_earthquakes`, `create_earthquake_map`, `get_earthquake_stats`
460
- """)
461
 
462
  with gr.Row():
463
  with gr.Column():
@@ -469,26 +458,21 @@ with gr.Blocks(title="Earthquake Data MCP Server", theme=gr.themes.Soft()) as ap
469
  mcp_submit_button = gr.Button("📤 Send MCP Request", variant="primary")
470
 
471
  with gr.Column():
472
- mcp_response_output = gr.Code(
473
- label="MCP Response",
474
- language="json"
475
- )
476
 
 
477
  mcp_submit_button.click(
478
- fn=gradio_handle_mcp_request,
479
  inputs=[mcp_request_input],
480
  outputs=[mcp_response_output]
481
  )
482
 
483
- # Example requests
484
  gr.Markdown("#### Example Requests:")
485
-
486
  example_requests = [
487
  ("List Tools", '{\n "jsonrpc": "2.0",\n "id": 2,\n "method": "tools/list",\n "params": {}\n}'),
488
  ("Query Earthquakes", '{\n "jsonrpc": "2.0",\n "id": 3,\n "method": "tools/call",\n "params": {\n "name": "query_earthquakes",\n "arguments": {\n "start_date": "2024-04-01",\n "end_date": "2024-04-30",\n "minimum_magnitude": 5.0\n }\n }\n}'),
489
  ("Get Statistics", '{\n "jsonrpc": "2.0",\n "id": 4,\n "method": "tools/call",\n "params": {\n "name": "get_earthquake_stats",\n "arguments": {\n "start_date": "2024-01-01",\n "end_date": "2024-06-30",\n "minimum_magnitude": 6.0\n }\n }\n}')
490
  ]
491
-
492
  for title, request in example_requests:
493
  with gr.Accordion(title, open=False):
494
  gr.Code(value=request, language="json")
@@ -497,9 +481,7 @@ with gr.Blocks(title="Earthquake Data MCP Server", theme=gr.themes.Soft()) as ap
497
  with gr.TabItem("📚 API Documentation"):
498
  gr.Markdown("""
499
  # API Documentation
500
-
501
  ## MCP Server Tools
502
-
503
  ### 1. query_earthquakes
504
  Query earthquake data.
505
  **Parameters:**
@@ -523,15 +505,10 @@ with gr.Blocks(title="Earthquake Data MCP Server", theme=gr.themes.Soft()) as ap
523
 
524
  # --- Main Application ---
525
  if __name__ == "__main__":
526
- # Check if running in Hugging Face Spaces
527
  import os
528
  port = int(os.environ.get("PORT", 7860))
529
 
530
  logger.info("Starting Earthquake Data MCP Server...")
531
  logger.info(f"Server will be available at: http://0.0.0.0:{port}")
532
 
533
- app.launch(
534
- server_name="0.0.0.0",
535
- server_port=port,
536
- mcp_server=True
537
- )
 
13
  import cartopy.feature as cfeature
14
  import base64
15
  import io
16
+ from typing import Any, Dict, Tuple
 
17
  import gradio as gr
18
  import logging
19
 
 
159
  image_base64 = base64.b64encode(buffer.getvalue()).decode()
160
  result["map_image_base64"] = image_base64
161
  buffer.close()
162
+ plt.close(fig) # Close the figure to free memory
163
 
164
  return result
165
 
 
282
  "capabilities": {"tools": {}},
283
  "serverInfo": {
284
  "name": "earthquake-data-server",
285
+ "version": "1.2.0" # Version bump
286
  }
287
  }
288
  }
 
305
 
306
  if tool_name == "query_earthquakes":
307
  result = await self.data_service.query_earthquakes_data(**arguments)
 
308
  result.pop("dataframe", None)
309
  elif tool_name == "create_earthquake_map":
310
  result = await self.data_service.create_earthquake_map(**arguments)
 
311
  result.pop("figure", None)
312
  elif tool_name == "get_earthquake_stats":
313
  result = await self.data_service.get_earthquake_stats(**arguments)
 
339
  }
340
 
341
  except Exception as e:
342
+ logger.error(f"Error handling MCP request: {e}", exc_info=True)
343
  return {
344
  "jsonrpc": "2.0",
345
  "id": request.get("id", 0),
 
347
  }
348
 
349
 
350
+ # Global instances
351
  data_service = EarthquakeDataService()
352
  mcp_server = EarthquakeMCPServer(data_service)
353
 
354
  # --- Gradio Interface Functions ---
355
+
356
  async def fetch_and_plot_data(
357
  start_date: str, end_date: str, minimum_magnitude: float
358
  ) -> Tuple[pd.DataFrame, Any]:
359
+ """Gradio interface function for fetching data and creating a plot."""
360
  try:
361
+ query_result = await data_service.query_earthquakes_data(
 
362
  start_date=start_date,
363
  end_date=end_date,
364
  minimum_magnitude=minimum_magnitude
365
  )
366
 
367
+ df = query_result.get("dataframe", pd.DataFrame())
368
+
369
+ if query_result.get("count", 0) == 0:
370
+ return df, None
371
+
372
+ map_result = await data_service.create_earthquake_map(
373
  start_date=start_date,
374
  end_date=end_date,
375
  minimum_magnitude=minimum_magnitude
376
  )
377
 
 
378
  figure = map_result.get("figure")
 
379
  return df, figure
380
 
381
  except Exception as e:
382
+ logger.error(f"Error in fetch_and_plot_data: {e}", exc_info=True)
 
 
 
 
 
 
 
 
383
  return pd.DataFrame({"Error": [str(e)]}), None
384
 
385
 
 
389
  request = json.loads(request_json)
390
  response = await mcp_server.handle_mcp_request(request)
391
  return json.dumps(response, indent=2, ensure_ascii=False)
392
+ except json.JSONDecodeError as e:
393
+ logger.error(f"JSON Parse Error: {e}")
394
  error_response = {
395
  "jsonrpc": "2.0",
396
  "id": None,
397
+ "error": {"code": -32700, "message": f"Parse error: {e}"}
398
  }
399
  return json.dumps(error_response, indent=2)
 
 
 
 
 
400
  except Exception as e:
401
+ logger.error(f"Error in handle_mcp_request_gradio: {e}", exc_info=True)
402
+ error_response = {
403
+ "jsonrpc": "2.0",
404
+ "id": None, # ID may not be available if parsing failed
405
+ "error": {"code": -32603, "message": f"Internal server error: {e}"}
406
+ }
407
+ return json.dumps(error_response, indent=2)
408
 
409
  # --- Gradio Interface ---
410
  with gr.Blocks(title="Earthquake Data MCP Server", theme=gr.themes.Soft()) as app:
 
434
  with gr.Column(scale=3):
435
  output_df = gr.DataFrame(label="Filtered Results")
436
 
437
+ # CORRECTED: Call the async function directly
438
  filter_button.click(
439
+ fn=fetch_and_plot_data,
440
  inputs=[
441
  start_date_input, end_date_input, minimum_magnitude_input
442
  ],
 
446
  # MCP Interface Tab
447
  with gr.TabItem("🔌 MCP Interface"):
448
  gr.Markdown("### Model Context Protocol (MCP) Interface")
449
+ gr.Markdown("Interact with the MCP server directly. **Available Tools:** `query_earthquakes`, `create_earthquake_map`, `get_earthquake_stats`")
 
 
 
 
450
 
451
  with gr.Row():
452
  with gr.Column():
 
458
  mcp_submit_button = gr.Button("📤 Send MCP Request", variant="primary")
459
 
460
  with gr.Column():
461
+ mcp_response_output = gr.Code(label="MCP Response", language="json")
 
 
 
462
 
463
+ # CORRECTED: Call the async function directly
464
  mcp_submit_button.click(
465
+ fn=handle_mcp_request_gradio,
466
  inputs=[mcp_request_input],
467
  outputs=[mcp_response_output]
468
  )
469
 
 
470
  gr.Markdown("#### Example Requests:")
 
471
  example_requests = [
472
  ("List Tools", '{\n "jsonrpc": "2.0",\n "id": 2,\n "method": "tools/list",\n "params": {}\n}'),
473
  ("Query Earthquakes", '{\n "jsonrpc": "2.0",\n "id": 3,\n "method": "tools/call",\n "params": {\n "name": "query_earthquakes",\n "arguments": {\n "start_date": "2024-04-01",\n "end_date": "2024-04-30",\n "minimum_magnitude": 5.0\n }\n }\n}'),
474
  ("Get Statistics", '{\n "jsonrpc": "2.0",\n "id": 4,\n "method": "tools/call",\n "params": {\n "name": "get_earthquake_stats",\n "arguments": {\n "start_date": "2024-01-01",\n "end_date": "2024-06-30",\n "minimum_magnitude": 6.0\n }\n }\n}')
475
  ]
 
476
  for title, request in example_requests:
477
  with gr.Accordion(title, open=False):
478
  gr.Code(value=request, language="json")
 
481
  with gr.TabItem("📚 API Documentation"):
482
  gr.Markdown("""
483
  # API Documentation
 
484
  ## MCP Server Tools
 
485
  ### 1. query_earthquakes
486
  Query earthquake data.
487
  **Parameters:**
 
505
 
506
  # --- Main Application ---
507
  if __name__ == "__main__":
 
508
  import os
509
  port = int(os.environ.get("PORT", 7860))
510
 
511
  logger.info("Starting Earthquake Data MCP Server...")
512
  logger.info(f"Server will be available at: http://0.0.0.0:{port}")
513
 
514
+ app.launch(server_name="0.0.0.0", server_port=port)