Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Hugging Face Spaces frontend for UniversalAPIAgentTool | |
| Connects to Modal Labs backend for API execution | |
| """ | |
| import gradio as gr | |
| import requests | |
| import json | |
| import time | |
| from typing import Dict, Any, Optional | |
| # Modal backend URL (will be updated after deployment) | |
| MODAL_BACKEND_URL = "https://jomasego--execute-api-call.modal.run" | |
| def execute_api_call_via_modal( | |
| base_url: str, | |
| endpoint: str, | |
| method: str = "GET", | |
| headers: str = "", | |
| params: str = "", | |
| json_body: str = "", | |
| timeout: int = 30 | |
| ) -> tuple: | |
| """ | |
| Execute API call via Modal Labs backend | |
| """ | |
| try: | |
| # Prepare request data for Modal backend | |
| request_data = { | |
| "base_url": base_url, | |
| "endpoint": endpoint, | |
| "method": method, | |
| "headers": headers, | |
| "params": params, | |
| "json_body": json_body, | |
| "timeout": timeout | |
| } | |
| # Call Modal backend | |
| start_time = time.time() | |
| response = requests.post( | |
| MODAL_BACKEND_URL, | |
| json=request_data, | |
| timeout=60 # Give Modal more time | |
| ) | |
| modal_execution_time = time.time() - start_time | |
| if response.status_code == 200: | |
| result = response.json() | |
| # Format the response for display | |
| status_code = result.get("status_code", 0) | |
| response_headers = result.get("response_headers", {}) | |
| response_body = result.get("response_body", "") | |
| execution_time = result.get("execution_time", 0.0) | |
| error_message = result.get("error_message") | |
| # Create formatted output | |
| output_lines = [ | |
| f"π **API Call Executed via Modal Labs**", | |
| f"β±οΈ **Execution Time**: {execution_time:.3f}s (Modal: {modal_execution_time:.3f}s)", | |
| f"π **Status Code**: {status_code}", | |
| "" | |
| ] | |
| if error_message: | |
| output_lines.extend([ | |
| f"β **Error**: {error_message}", | |
| "" | |
| ]) | |
| if response_headers: | |
| output_lines.extend([ | |
| "π **Response Headers**:", | |
| "```json", | |
| json.dumps(response_headers, indent=2), | |
| "```", | |
| "" | |
| ]) | |
| if response_body: | |
| output_lines.extend([ | |
| "π **Response Body**:", | |
| "```json" if response_body.strip().startswith(('{', '[')) else "```", | |
| response_body, | |
| "```" | |
| ]) | |
| return "\n".join(output_lines), f"Status: {status_code}" | |
| else: | |
| return f"β **Modal Backend Error**\nStatus: {response.status_code}\nResponse: {response.text}", "Modal Error" | |
| except requests.exceptions.Timeout: | |
| return "β **Timeout Error**\nModal backend request timed out", "Timeout" | |
| except requests.exceptions.ConnectionError: | |
| return "β **Connection Error**\nCannot connect to Modal backend", "Connection Error" | |
| except Exception as e: | |
| return f"β **Error**\n{str(e)}", "Error" | |
| def create_gradio_interface(): | |
| """Create the Gradio interface""" | |
| # Example configurations | |
| examples = [ | |
| [ | |
| "https://api.coingecko.com", | |
| "/api/v3/simple/price", | |
| "GET", | |
| "", | |
| '{"ids": "bitcoin,ethereum", "vs_currencies": "usd"}', | |
| "", | |
| 30 | |
| ], | |
| [ | |
| "https://api.github.com", | |
| "/repos/microsoft/vscode", | |
| "GET", | |
| "", | |
| "", | |
| "", | |
| 30 | |
| ], | |
| [ | |
| "https://jsonplaceholder.typicode.com", | |
| "/posts", | |
| "POST", | |
| '{"Content-Type": "application/json"}', | |
| "", | |
| '{"title": "Test Post", "body": "This is a test", "userId": 1}', | |
| 30 | |
| ] | |
| ] | |
| with gr.Blocks( | |
| title="UniversalAPIAgentTool - HF Spaces + Modal Labs", | |
| theme=gr.themes.Soft(), | |
| css=""" | |
| .gradio-container { | |
| max-width: 1200px !important; | |
| } | |
| .tab-nav { | |
| background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); | |
| } | |
| """ | |
| ) as interface: | |
| gr.Markdown(""" | |
| # π UniversalAPIAgentTool | |
| **Powered by Hugging Face Spaces + Modal Labs** | |
| Universal MCP tool that enables AI agents to access any REST API. This frontend runs on HF Spaces while the backend executes on Modal Labs for optimal performance. | |
| """) | |
| with gr.Tab("π§ API Executor"): | |
| gr.Markdown("### Execute HTTP requests to any REST API") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| base_url = gr.Textbox( | |
| label="Base URL", | |
| placeholder="https://api.example.com", | |
| value="https://api.coingecko.com" | |
| ) | |
| endpoint = gr.Textbox( | |
| label="Endpoint", | |
| placeholder="/api/v1/resource", | |
| value="/api/v3/simple/price" | |
| ) | |
| with gr.Column(scale=1): | |
| method = gr.Dropdown( | |
| choices=["GET", "POST", "PUT", "DELETE", "PATCH"], | |
| value="GET", | |
| label="HTTP Method" | |
| ) | |
| timeout = gr.Slider( | |
| minimum=5, | |
| maximum=120, | |
| value=30, | |
| step=5, | |
| label="Timeout (seconds)" | |
| ) | |
| with gr.Row(): | |
| headers = gr.Textbox( | |
| label="Headers (JSON)", | |
| placeholder='{"Authorization": "Bearer token", "Content-Type": "application/json"}', | |
| lines=2 | |
| ) | |
| params = gr.Textbox( | |
| label="Query Parameters (JSON)", | |
| placeholder='{"key": "value", "limit": 10}', | |
| lines=2, | |
| value='{"ids": "bitcoin,ethereum", "vs_currencies": "usd"}' | |
| ) | |
| json_body = gr.Textbox( | |
| label="JSON Body (for POST/PUT)", | |
| placeholder='{"name": "value", "data": [1, 2, 3]}', | |
| lines=3 | |
| ) | |
| with gr.Row(): | |
| execute_btn = gr.Button("π Execute API Call", variant="primary", size="lg") | |
| clear_btn = gr.Button("ποΈ Clear", variant="secondary") | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| output = gr.Markdown(label="Response") | |
| with gr.Column(scale=1): | |
| status = gr.Textbox(label="Status", interactive=False) | |
| # Examples | |
| gr.Markdown("### π Quick Examples") | |
| gr.Examples( | |
| examples=examples, | |
| inputs=[base_url, endpoint, method, headers, params, json_body, timeout], | |
| label="Try these examples" | |
| ) | |
| with gr.Tab("π Documentation"): | |
| gr.Markdown(""" | |
| ## π― How to Use | |
| 1. **Base URL**: The root URL of the API (e.g., `https://api.github.com`) | |
| 2. **Endpoint**: The specific path (e.g., `/repos/owner/repo`) | |
| 3. **Method**: HTTP method (GET, POST, PUT, DELETE, PATCH) | |
| 4. **Headers**: Authentication and content type headers as JSON | |
| 5. **Parameters**: URL query parameters as JSON | |
| 6. **JSON Body**: Request payload for POST/PUT requests | |
| ## π Authentication Examples | |
| ### API Key in Headers | |
| ```json | |
| {"X-API-Key": "your-api-key-here"} | |
| ``` | |
| ### Bearer Token | |
| ```json | |
| {"Authorization": "Bearer your-token-here"} | |
| ``` | |
| ### Basic Auth (base64 encoded) | |
| ```json | |
| {"Authorization": "Basic dXNlcjpwYXNz"} | |
| ``` | |
| ## π Example APIs to Try | |
| ### πͺ Cryptocurrency Prices (CoinGecko) | |
| - **URL**: `https://api.coingecko.com` | |
| - **Endpoint**: `/api/v3/simple/price` | |
| - **Params**: `{"ids": "bitcoin", "vs_currencies": "usd"}` | |
| ### π GitHub Repository Info | |
| - **URL**: `https://api.github.com` | |
| - **Endpoint**: `/repos/microsoft/vscode` | |
| - **Method**: GET | |
| ### π Country Information | |
| - **URL**: `https://restcountries.com` | |
| - **Endpoint**: `/v3.1/name/germany` | |
| - **Method**: GET | |
| ### π Test POST Requests | |
| - **URL**: `https://jsonplaceholder.typicode.com` | |
| - **Endpoint**: `/posts` | |
| - **Method**: POST | |
| - **Headers**: `{"Content-Type": "application/json"}` | |
| - **Body**: `{"title": "Test", "body": "Content", "userId": 1}` | |
| ## π€ For AI Agents (MCP) | |
| This tool can be used by AI agents via MCP with this function call: | |
| ```json | |
| { | |
| "tool_name": "UniversalAPIAgentTool", | |
| "function_name": "execute_api_call", | |
| "parameters": { | |
| "base_url": "https://api.example.com", | |
| "endpoint": "/v1/resource", | |
| "method": "GET", | |
| "headers": {"Authorization": "Bearer token"}, | |
| "params": {"query": "value"}, | |
| "json_body": {"data": "value"} | |
| } | |
| } | |
| ``` | |
| ## ποΈ Architecture | |
| - **Frontend**: Hugging Face Spaces (Gradio) | |
| - **Backend**: Modal Labs (Python + FastAPI) | |
| - **Benefits**: Scalable, fast, and reliable API execution | |
| ## π Hackathon Project | |
| Built for the **Agents & MCP Hackathon** to demonstrate how MCP can expand AI agent capabilities through universal API access. | |
| """) | |
| with gr.Tab("π§ Backend Status"): | |
| gr.Markdown(f""" | |
| ## π₯οΈ Modal Labs Backend | |
| **Backend URL**: `{MODAL_BACKEND_URL}` | |
| The backend is hosted on Modal Labs for optimal performance and scalability. | |
| """) | |
| def check_backend_health(): | |
| try: | |
| health_url = MODAL_BACKEND_URL.replace("execute-api-call", "health-check") | |
| response = requests.get(health_url, timeout=10) | |
| if response.status_code == 200: | |
| data = response.json() | |
| return f"β **Backend Status**: Healthy\n**Service**: {data.get('service', 'Unknown')}\n**Version**: {data.get('version', 'Unknown')}" | |
| else: | |
| return f"β οΈ **Backend Status**: Unhealthy (Status: {response.status_code})" | |
| except Exception as e: | |
| return f"β **Backend Status**: Error - {str(e)}" | |
| health_output = gr.Markdown() | |
| health_btn = gr.Button("π Check Backend Health") | |
| health_btn.click(fn=check_backend_health, outputs=health_output) | |
| # Event handlers | |
| execute_btn.click( | |
| fn=execute_api_call_via_modal, | |
| inputs=[base_url, endpoint, method, headers, params, json_body, timeout], | |
| outputs=[output, status] | |
| ) | |
| def clear_inputs(): | |
| return "", "", "GET", "", "", "", 30 | |
| clear_btn.click( | |
| fn=clear_inputs, | |
| outputs=[base_url, endpoint, method, headers, params, json_body, timeout] | |
| ) | |
| return interface | |
| if __name__ == "__main__": | |
| # Create and launch the interface | |
| interface = create_gradio_interface() | |
| interface.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| show_error=True | |
| ) | |