jomasego commited on
Commit
bd97c5d
Β·
verified Β·
1 Parent(s): ba88404

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +356 -0
app.py ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Hugging Face Spaces frontend for UniversalAPIAgentTool
4
+ Connects to Modal Labs backend for API execution
5
+ """
6
+
7
+ import gradio as gr
8
+ import requests
9
+ import json
10
+ import time
11
+ from typing import Dict, Any, Optional
12
+
13
+ # Modal backend URL (will be updated after deployment)
14
+ MODAL_BACKEND_URL = "https://jomasego--execute-api-call.modal.run"
15
+
16
+ def execute_api_call_via_modal(
17
+ base_url: str,
18
+ endpoint: str,
19
+ method: str = "GET",
20
+ headers: str = "",
21
+ params: str = "",
22
+ json_body: str = "",
23
+ timeout: int = 30
24
+ ) -> tuple:
25
+ """
26
+ Execute API call via Modal Labs backend
27
+ """
28
+ try:
29
+ # Prepare request data for Modal backend
30
+ request_data = {
31
+ "base_url": base_url,
32
+ "endpoint": endpoint,
33
+ "method": method,
34
+ "headers": headers,
35
+ "params": params,
36
+ "json_body": json_body,
37
+ "timeout": timeout
38
+ }
39
+
40
+ # Call Modal backend
41
+ start_time = time.time()
42
+ response = requests.post(
43
+ MODAL_BACKEND_URL,
44
+ json=request_data,
45
+ timeout=60 # Give Modal more time
46
+ )
47
+ modal_execution_time = time.time() - start_time
48
+
49
+ if response.status_code == 200:
50
+ result = response.json()
51
+
52
+ # Format the response for display
53
+ status_code = result.get("status_code", 0)
54
+ response_headers = result.get("response_headers", {})
55
+ response_body = result.get("response_body", "")
56
+ execution_time = result.get("execution_time", 0.0)
57
+ error_message = result.get("error_message")
58
+
59
+ # Create formatted output
60
+ output_lines = [
61
+ f"πŸš€ **API Call Executed via Modal Labs**",
62
+ f"⏱️ **Execution Time**: {execution_time:.3f}s (Modal: {modal_execution_time:.3f}s)",
63
+ f"πŸ“Š **Status Code**: {status_code}",
64
+ ""
65
+ ]
66
+
67
+ if error_message:
68
+ output_lines.extend([
69
+ f"❌ **Error**: {error_message}",
70
+ ""
71
+ ])
72
+
73
+ if response_headers:
74
+ output_lines.extend([
75
+ "πŸ“‹ **Response Headers**:",
76
+ "```json",
77
+ json.dumps(response_headers, indent=2),
78
+ "```",
79
+ ""
80
+ ])
81
+
82
+ if response_body:
83
+ output_lines.extend([
84
+ "πŸ“„ **Response Body**:",
85
+ "```json" if response_body.strip().startswith(('{', '[')) else "```",
86
+ response_body,
87
+ "```"
88
+ ])
89
+
90
+ return "\n".join(output_lines), f"Status: {status_code}"
91
+
92
+ else:
93
+ return f"❌ **Modal Backend Error**\nStatus: {response.status_code}\nResponse: {response.text}", "Modal Error"
94
+
95
+ except requests.exceptions.Timeout:
96
+ return "❌ **Timeout Error**\nModal backend request timed out", "Timeout"
97
+ except requests.exceptions.ConnectionError:
98
+ return "❌ **Connection Error**\nCannot connect to Modal backend", "Connection Error"
99
+ except Exception as e:
100
+ return f"❌ **Error**\n{str(e)}", "Error"
101
+
102
+ def create_gradio_interface():
103
+ """Create the Gradio interface"""
104
+
105
+ # Example configurations
106
+ examples = [
107
+ [
108
+ "https://api.coingecko.com",
109
+ "/api/v3/simple/price",
110
+ "GET",
111
+ "",
112
+ '{"ids": "bitcoin,ethereum", "vs_currencies": "usd"}',
113
+ "",
114
+ 30
115
+ ],
116
+ [
117
+ "https://api.github.com",
118
+ "/repos/microsoft/vscode",
119
+ "GET",
120
+ "",
121
+ "",
122
+ "",
123
+ 30
124
+ ],
125
+ [
126
+ "https://jsonplaceholder.typicode.com",
127
+ "/posts",
128
+ "POST",
129
+ '{"Content-Type": "application/json"}',
130
+ "",
131
+ '{"title": "Test Post", "body": "This is a test", "userId": 1}',
132
+ 30
133
+ ]
134
+ ]
135
+
136
+ with gr.Blocks(
137
+ title="UniversalAPIAgentTool - HF Spaces + Modal Labs",
138
+ theme=gr.themes.Soft(),
139
+ css="""
140
+ .gradio-container {
141
+ max-width: 1200px !important;
142
+ }
143
+ .tab-nav {
144
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
145
+ }
146
+ """
147
+ ) as interface:
148
+
149
+ gr.Markdown("""
150
+ # πŸš€ UniversalAPIAgentTool
151
+
152
+ **Powered by Hugging Face Spaces + Modal Labs**
153
+
154
+ 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.
155
+ """)
156
+
157
+ with gr.Tab("πŸ”§ API Executor"):
158
+ gr.Markdown("### Execute HTTP requests to any REST API")
159
+
160
+ with gr.Row():
161
+ with gr.Column(scale=2):
162
+ base_url = gr.Textbox(
163
+ label="Base URL",
164
+ placeholder="https://api.example.com",
165
+ value="https://api.coingecko.com"
166
+ )
167
+ endpoint = gr.Textbox(
168
+ label="Endpoint",
169
+ placeholder="/api/v1/resource",
170
+ value="/api/v3/simple/price"
171
+ )
172
+
173
+ with gr.Column(scale=1):
174
+ method = gr.Dropdown(
175
+ choices=["GET", "POST", "PUT", "DELETE", "PATCH"],
176
+ value="GET",
177
+ label="HTTP Method"
178
+ )
179
+ timeout = gr.Slider(
180
+ minimum=5,
181
+ maximum=120,
182
+ value=30,
183
+ step=5,
184
+ label="Timeout (seconds)"
185
+ )
186
+
187
+ with gr.Row():
188
+ headers = gr.Textbox(
189
+ label="Headers (JSON)",
190
+ placeholder='{"Authorization": "Bearer token", "Content-Type": "application/json"}',
191
+ lines=2
192
+ )
193
+ params = gr.Textbox(
194
+ label="Query Parameters (JSON)",
195
+ placeholder='{"key": "value", "limit": 10}',
196
+ lines=2,
197
+ value='{"ids": "bitcoin,ethereum", "vs_currencies": "usd"}'
198
+ )
199
+
200
+ json_body = gr.Textbox(
201
+ label="JSON Body (for POST/PUT)",
202
+ placeholder='{"name": "value", "data": [1, 2, 3]}',
203
+ lines=3
204
+ )
205
+
206
+ with gr.Row():
207
+ execute_btn = gr.Button("πŸš€ Execute API Call", variant="primary", size="lg")
208
+ clear_btn = gr.Button("πŸ—‘οΈ Clear", variant="secondary")
209
+
210
+ with gr.Row():
211
+ with gr.Column(scale=3):
212
+ output = gr.Markdown(label="Response")
213
+ with gr.Column(scale=1):
214
+ status = gr.Textbox(label="Status", interactive=False)
215
+
216
+ # Examples
217
+ gr.Markdown("### πŸ“ Quick Examples")
218
+ gr.Examples(
219
+ examples=examples,
220
+ inputs=[base_url, endpoint, method, headers, params, json_body, timeout],
221
+ label="Try these examples"
222
+ )
223
+
224
+ with gr.Tab("πŸ“š Documentation"):
225
+ gr.Markdown("""
226
+ ## 🎯 How to Use
227
+
228
+ 1. **Base URL**: The root URL of the API (e.g., `https://api.github.com`)
229
+ 2. **Endpoint**: The specific path (e.g., `/repos/owner/repo`)
230
+ 3. **Method**: HTTP method (GET, POST, PUT, DELETE, PATCH)
231
+ 4. **Headers**: Authentication and content type headers as JSON
232
+ 5. **Parameters**: URL query parameters as JSON
233
+ 6. **JSON Body**: Request payload for POST/PUT requests
234
+
235
+ ## πŸ” Authentication Examples
236
+
237
+ ### API Key in Headers
238
+ ```json
239
+ {"X-API-Key": "your-api-key-here"}
240
+ ```
241
+
242
+ ### Bearer Token
243
+ ```json
244
+ {"Authorization": "Bearer your-token-here"}
245
+ ```
246
+
247
+ ### Basic Auth (base64 encoded)
248
+ ```json
249
+ {"Authorization": "Basic dXNlcjpwYXNz"}
250
+ ```
251
+
252
+ ## 🌐 Example APIs to Try
253
+
254
+ ### πŸͺ™ Cryptocurrency Prices (CoinGecko)
255
+ - **URL**: `https://api.coingecko.com`
256
+ - **Endpoint**: `/api/v3/simple/price`
257
+ - **Params**: `{"ids": "bitcoin", "vs_currencies": "usd"}`
258
+
259
+ ### πŸ™ GitHub Repository Info
260
+ - **URL**: `https://api.github.com`
261
+ - **Endpoint**: `/repos/microsoft/vscode`
262
+ - **Method**: GET
263
+
264
+ ### 🌍 Country Information
265
+ - **URL**: `https://restcountries.com`
266
+ - **Endpoint**: `/v3.1/name/germany`
267
+ - **Method**: GET
268
+
269
+ ### πŸ“ Test POST Requests
270
+ - **URL**: `https://jsonplaceholder.typicode.com`
271
+ - **Endpoint**: `/posts`
272
+ - **Method**: POST
273
+ - **Headers**: `{"Content-Type": "application/json"}`
274
+ - **Body**: `{"title": "Test", "body": "Content", "userId": 1}`
275
+
276
+ ## πŸ€– For AI Agents (MCP)
277
+
278
+ This tool can be used by AI agents via MCP with this function call:
279
+
280
+ ```json
281
+ {
282
+ "tool_name": "UniversalAPIAgentTool",
283
+ "function_name": "execute_api_call",
284
+ "parameters": {
285
+ "base_url": "https://api.example.com",
286
+ "endpoint": "/v1/resource",
287
+ "method": "GET",
288
+ "headers": {"Authorization": "Bearer token"},
289
+ "params": {"query": "value"},
290
+ "json_body": {"data": "value"}
291
+ }
292
+ }
293
+ ```
294
+
295
+ ## πŸ—οΈ Architecture
296
+
297
+ - **Frontend**: Hugging Face Spaces (Gradio)
298
+ - **Backend**: Modal Labs (Python + FastAPI)
299
+ - **Benefits**: Scalable, fast, and reliable API execution
300
+
301
+ ## πŸ† Hackathon Project
302
+
303
+ Built for the **Agents & MCP Hackathon** to demonstrate how MCP can expand AI agent capabilities through universal API access.
304
+ """)
305
+
306
+ with gr.Tab("πŸ”§ Backend Status"):
307
+ gr.Markdown(f"""
308
+ ## πŸ–₯️ Modal Labs Backend
309
+
310
+ **Backend URL**: `{MODAL_BACKEND_URL}`
311
+
312
+ The backend is hosted on Modal Labs for optimal performance and scalability.
313
+ """)
314
+
315
+ def check_backend_health():
316
+ try:
317
+ health_url = MODAL_BACKEND_URL.replace("execute-api-call", "health-check")
318
+ response = requests.get(health_url, timeout=10)
319
+ if response.status_code == 200:
320
+ data = response.json()
321
+ return f"βœ… **Backend Status**: Healthy\n**Service**: {data.get('service', 'Unknown')}\n**Version**: {data.get('version', 'Unknown')}"
322
+ else:
323
+ return f"⚠️ **Backend Status**: Unhealthy (Status: {response.status_code})"
324
+ except Exception as e:
325
+ return f"❌ **Backend Status**: Error - {str(e)}"
326
+
327
+ health_output = gr.Markdown()
328
+ health_btn = gr.Button("πŸ” Check Backend Health")
329
+ health_btn.click(fn=check_backend_health, outputs=health_output)
330
+
331
+ # Event handlers
332
+ execute_btn.click(
333
+ fn=execute_api_call_via_modal,
334
+ inputs=[base_url, endpoint, method, headers, params, json_body, timeout],
335
+ outputs=[output, status]
336
+ )
337
+
338
+ def clear_inputs():
339
+ return "", "", "GET", "", "", "", 30
340
+
341
+ clear_btn.click(
342
+ fn=clear_inputs,
343
+ outputs=[base_url, endpoint, method, headers, params, json_body, timeout]
344
+ )
345
+
346
+ return interface
347
+
348
+ if __name__ == "__main__":
349
+ # Create and launch the interface
350
+ interface = create_gradio_interface()
351
+ interface.launch(
352
+ server_name="0.0.0.0",
353
+ server_port=7860,
354
+ share=False,
355
+ show_error=True
356
+ )