Spaces:
Running
Running
Commit
·
c912400
1
Parent(s):
1891daa
Spewed some formatting code for database data retrieval; will have to wait for actual database entries to further test
Browse files- api_monitor.py +247 -30
- main.py +39 -3
api_monitor.py
CHANGED
@@ -391,7 +391,7 @@ def activate_monitoring(config_id, mcp_api_key):
|
|
391 |
}
|
392 |
|
393 |
|
394 |
-
def retrieve_monitored_data(config_id, mcp_api_key):
|
395 |
"""
|
396 |
TOOL: Retrieve monitored data for a specific API configuration.
|
397 |
|
@@ -400,11 +400,10 @@ def retrieve_monitored_data(config_id, mcp_api_key):
|
|
400 |
|
401 |
PREREQUISITE: Must call validate_api_configuration() first and obtain a config_id from successful validation, then activate_monitoring() to start monitoring.
|
402 |
|
403 |
-
This function can be called at any time after monitoring activation to retrieve the latest data collected by the monitoring system.
|
404 |
-
|
405 |
-
Parameters:
|
406 |
- config_id: The ID of the API configuration to retrieve data for (required)
|
407 |
- mcp_api_key: User's MCP API key for verification (must match validation step)
|
|
|
408 |
|
409 |
Input Examples:
|
410 |
1. Retrieve data for stock monitoring:
|
@@ -413,28 +412,71 @@ def retrieve_monitored_data(config_id, mcp_api_key):
|
|
413 |
|
414 |
2. Retrieve data for weather alerts:
|
415 |
config_id: 987654321
|
416 |
-
mcp_api_key: "your_mcp_key_here"
|
|
|
417 |
|
418 |
-
|
419 |
-
- Dictionary with success status, data, and message
|
420 |
-
- If no data found, returns success=False with appropriate message
|
421 |
-
Example return:
|
422 |
{
|
423 |
"success": True,
|
424 |
-
"
|
425 |
-
|
426 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
427 |
],
|
428 |
-
"
|
|
|
|
|
|
|
|
|
429 |
}
|
430 |
-
- If config_id not found or invalid, returns success=False with error message
|
431 |
-
- If mcp_api_key does not match, returns success=False with error message
|
432 |
|
433 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
434 |
{
|
435 |
"success": False,
|
436 |
-
"message": "Invalid config_id or mcp_api_key"
|
437 |
-
"data": []
|
438 |
}
|
439 |
ERROR HANDLING: If config_id not found or invalid, returns success=False with error message
|
440 |
"""
|
@@ -444,25 +486,200 @@ def retrieve_monitored_data(config_id, mcp_api_key):
|
|
444 |
cur.execute(
|
445 |
"SELECT * FROM api_configurations WHERE config_id = %s", (config_id,)
|
446 |
)
|
447 |
-
|
448 |
|
449 |
-
if not
|
450 |
conn.close()
|
451 |
return {
|
452 |
"success": False,
|
453 |
"message": "Invalid config_id",
|
454 |
"data": [],
|
455 |
}
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
465 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
466 |
except Exception as e:
|
467 |
return {
|
468 |
"success": False,
|
@@ -503,4 +720,4 @@ if __name__ == "__main__":
|
|
503 |
config_id=activate_monitoring_response.get("config_id"),
|
504 |
mcp_api_key="your_api_key",
|
505 |
)
|
506 |
-
print(response)
|
|
|
391 |
}
|
392 |
|
393 |
|
394 |
+
def retrieve_monitored_data(config_id, mcp_api_key, mode="summary"):
|
395 |
"""
|
396 |
TOOL: Retrieve monitored data for a specific API configuration.
|
397 |
|
|
|
400 |
|
401 |
PREREQUISITE: Must call validate_api_configuration() first and obtain a config_id from successful validation, then activate_monitoring() to start monitoring.
|
402 |
|
403 |
+
This function can be called at any time after monitoring activation to retrieve the latest data collected by the monitoring system. Parameters:
|
|
|
|
|
404 |
- config_id: The ID of the API configuration to retrieve data for (required)
|
405 |
- mcp_api_key: User's MCP API key for verification (must match validation step)
|
406 |
+
- mode: Data return mode - "summary" (LLM-optimized), "details" (full responses, minimal metadata), "full" (everything)
|
407 |
|
408 |
Input Examples:
|
409 |
1. Retrieve data for stock monitoring:
|
|
|
412 |
|
413 |
2. Retrieve data for weather alerts:
|
414 |
config_id: 987654321
|
415 |
+
mcp_api_key: "your_mcp_key_here" Returns:
|
416 |
+
- Dictionary with monitoring status in one of three formats based on mode parameter
|
417 |
|
418 |
+
SUMMARY mode (LLM-optimized, default):
|
|
|
|
|
|
|
419 |
{
|
420 |
"success": True,
|
421 |
+
"config_name": "Weather Alert Monitor",
|
422 |
+
"summary": {
|
423 |
+
"status": "active", // "active", "inactive"
|
424 |
+
"health": "good", // "good", "degraded", "no_data"
|
425 |
+
"calls_made": 15,
|
426 |
+
"success_rate": 93.3,
|
427 |
+
"last_call": "2025-06-05T15:20:00",
|
428 |
+
"last_success": "2025-06-05T15:20:00"
|
429 |
+
},
|
430 |
+
"recent_calls": [
|
431 |
+
{
|
432 |
+
"timestamp": "2025-06-05T15:20:00",
|
433 |
+
"success": true,
|
434 |
+
"error": null,
|
435 |
+
"response_preview": "{'alerts': [{'type': 'tornado'}]}..." // truncated
|
436 |
+
}
|
437 |
+
// ... up to 5 most recent calls
|
438 |
],
|
439 |
+
"full_data_available": 15,
|
440 |
+
"monitoring_details": {
|
441 |
+
"interval_minutes": 20,
|
442 |
+
"is_finished": false
|
443 |
+
}
|
444 |
}
|
|
|
|
|
445 |
|
446 |
+
DETAILS mode (full responses, minimal metadata):
|
447 |
+
{
|
448 |
+
"success": True,
|
449 |
+
"config_name": "Weather Alert Monitor",
|
450 |
+
"status": "active",
|
451 |
+
"calls_made": 15,
|
452 |
+
"success_rate": 93.3,
|
453 |
+
"recent_responses": [
|
454 |
+
{
|
455 |
+
"timestamp": "2025-06-05T15:20:00",
|
456 |
+
"success": true,
|
457 |
+
"response_data": {...}, // full response data
|
458 |
+
"error": null
|
459 |
+
}
|
460 |
+
// ... up to 10 most recent calls with full responses
|
461 |
+
]
|
462 |
+
}
|
463 |
+
|
464 |
+
FULL mode (everything):
|
465 |
+
{
|
466 |
+
"success": True,
|
467 |
+
"config_name": "Weather Alert Monitor",
|
468 |
+
"config_description": "Monitor severe weather alerts",
|
469 |
+
"is_active": True,
|
470 |
+
"is_finished": False,
|
471 |
+
"progress": {...},
|
472 |
+
"schedule_info": {...},
|
473 |
+
"data": [...] // all historical data
|
474 |
+
}
|
475 |
+
|
476 |
+
Error return format:
|
477 |
{
|
478 |
"success": False,
|
479 |
+
"message": "Invalid config_id or mcp_api_key"
|
|
|
480 |
}
|
481 |
ERROR HANDLING: If config_id not found or invalid, returns success=False with error message
|
482 |
"""
|
|
|
486 |
cur.execute(
|
487 |
"SELECT * FROM api_configurations WHERE config_id = %s", (config_id,)
|
488 |
)
|
489 |
+
config_row = cur.fetchone()
|
490 |
|
491 |
+
if not config_row:
|
492 |
conn.close()
|
493 |
return {
|
494 |
"success": False,
|
495 |
"message": "Invalid config_id",
|
496 |
"data": [],
|
497 |
}
|
498 |
+
|
499 |
+
config = dict(config_row)
|
500 |
+
print(f"Retrieved config: {config}")
|
501 |
+
|
502 |
+
if config["mcp_api_key"] != mcp_api_key:
|
503 |
+
conn.close()
|
504 |
+
return {
|
505 |
+
"success": False,
|
506 |
+
"message": "Invalid mcp_api_key. You are not authorized to access this configuration.",
|
507 |
+
"data": [],
|
508 |
+
}
|
509 |
+
|
510 |
+
# Query the api_call_results table for monitored data
|
511 |
+
cur.execute(
|
512 |
+
"SELECT * FROM api_call_results WHERE config_id = %s ORDER BY called_at DESC",
|
513 |
+
(config_id,),
|
514 |
+
)
|
515 |
+
monitored_data_rows = cur.fetchall()
|
516 |
+
|
517 |
+
# Convert rows to dictionaries and format timestamps
|
518 |
+
monitored_data = []
|
519 |
+
for row in monitored_data_rows:
|
520 |
+
row_dict = dict(row)
|
521 |
+
# Format the timestamp for better readability
|
522 |
+
if row_dict.get("called_at"):
|
523 |
+
row_dict["called_at"] = row_dict["called_at"].isoformat()
|
524 |
+
monitored_data.append(row_dict)
|
525 |
+
|
526 |
+
# Check if monitoring is finished
|
527 |
+
now = datetime.now()
|
528 |
+
stop_time = config.get("time_to_start")
|
529 |
+
if stop_time and config.get("schedule_interval_minutes"):
|
530 |
+
# Calculate when monitoring should stop
|
531 |
+
stop_after_hours = (
|
532 |
+
config.get("schedule_interval_minutes", 24) / 60 * 24
|
533 |
+
) # Default fallback
|
534 |
+
if hasattr(stop_time, "replace"):
|
535 |
+
stop_at = stop_time + timedelta(hours=stop_after_hours)
|
536 |
+
else:
|
537 |
+
stop_at = datetime.fromisoformat(str(stop_time)) + timedelta(
|
538 |
+
hours=stop_after_hours
|
539 |
+
)
|
540 |
+
is_finished = now > stop_at or config.get("stop", False)
|
541 |
+
else:
|
542 |
+
is_finished = config.get("stop", False)
|
543 |
+
|
544 |
+
# Calculate progress statistics
|
545 |
+
total_expected_calls = 0
|
546 |
+
if config.get("time_to_start") and config.get("schedule_interval_minutes"):
|
547 |
+
start_time = config["time_to_start"]
|
548 |
+
if hasattr(start_time, "replace"):
|
549 |
+
start_dt = start_time
|
550 |
+
else:
|
551 |
+
start_dt = datetime.fromisoformat(str(start_time))
|
552 |
+
|
553 |
+
elapsed_minutes = (now - start_dt).total_seconds() / 60
|
554 |
+
if elapsed_minutes > 0:
|
555 |
+
total_expected_calls = max(
|
556 |
+
1, int(elapsed_minutes / config["schedule_interval_minutes"])
|
557 |
+
)
|
558 |
+
|
559 |
+
# Get success/failure counts
|
560 |
+
successful_calls = len(
|
561 |
+
[d for d in monitored_data if d.get("is_successful", False)]
|
562 |
+
)
|
563 |
+
failed_calls = len(
|
564 |
+
[d for d in monitored_data if not d.get("is_successful", True)]
|
565 |
+
)
|
566 |
+
total_calls = len(
|
567 |
+
monitored_data
|
568 |
+
) # Create simplified summary for LLM consumption
|
569 |
+
summary = {
|
570 |
+
"status": (
|
571 |
+
"active"
|
572 |
+
if config.get("is_active", False) and not is_finished
|
573 |
+
else "inactive"
|
574 |
+
),
|
575 |
+
"health": (
|
576 |
+
"good"
|
577 |
+
if total_calls > 0 and (successful_calls / total_calls) > 0.8
|
578 |
+
else "degraded" if total_calls > 0 else "no_data"
|
579 |
+
),
|
580 |
+
"calls_made": total_calls,
|
581 |
+
"success_rate": (
|
582 |
+
round(successful_calls / total_calls * 100, 1) if total_calls > 0 else 0
|
583 |
+
),
|
584 |
+
"last_call": monitored_data[0]["called_at"] if monitored_data else None,
|
585 |
+
"last_success": next(
|
586 |
+
(d["called_at"] for d in monitored_data if d.get("is_successful")), None
|
587 |
+
),
|
588 |
}
|
589 |
+
|
590 |
+
# Handle different return modes
|
591 |
+
if mode == "full":
|
592 |
+
# Return complete detailed data (original detailed format)
|
593 |
+
return {
|
594 |
+
"success": True,
|
595 |
+
"message": f"Full data retrieved for config_id {config_id}",
|
596 |
+
"config_name": config.get("name", "Unknown"),
|
597 |
+
"config_description": config.get("description", ""),
|
598 |
+
"is_active": config.get("is_active", False),
|
599 |
+
"is_finished": is_finished,
|
600 |
+
"progress": {
|
601 |
+
"total_calls": total_calls,
|
602 |
+
"successful_calls": successful_calls,
|
603 |
+
"failed_calls": failed_calls,
|
604 |
+
"expected_calls": total_expected_calls,
|
605 |
+
"success_rate": (
|
606 |
+
round(successful_calls / total_calls * 100, 2)
|
607 |
+
if total_calls > 0
|
608 |
+
else 0
|
609 |
+
),
|
610 |
+
},
|
611 |
+
"schedule_info": {
|
612 |
+
"interval_minutes": config.get("schedule_interval_minutes"),
|
613 |
+
"started_at": (
|
614 |
+
config.get("time_to_start").isoformat()
|
615 |
+
if config.get("time_to_start")
|
616 |
+
else None
|
617 |
+
),
|
618 |
+
"is_stopped": config.get("stop", False),
|
619 |
+
},
|
620 |
+
"data": monitored_data,
|
621 |
+
}
|
622 |
+
|
623 |
+
elif mode == "details":
|
624 |
+
# Return full response data but minimal metadata (up to 10 recent calls)
|
625 |
+
recent_responses = []
|
626 |
+
for item in monitored_data[:10]: # Last 10 calls with full responses
|
627 |
+
recent_responses.append(
|
628 |
+
{
|
629 |
+
"timestamp": item["called_at"],
|
630 |
+
"success": item.get("is_successful", False),
|
631 |
+
"response_data": item.get(
|
632 |
+
"response_data"
|
633 |
+
), # Full response data
|
634 |
+
"error": (
|
635 |
+
item.get("error_message")
|
636 |
+
if not item.get("is_successful")
|
637 |
+
else None
|
638 |
+
),
|
639 |
+
}
|
640 |
+
)
|
641 |
+
|
642 |
+
return {
|
643 |
+
"success": True,
|
644 |
+
"config_name": config.get("name", "Unknown"),
|
645 |
+
"status": summary["status"],
|
646 |
+
"calls_made": total_calls,
|
647 |
+
"success_rate": summary["success_rate"],
|
648 |
+
"recent_responses": recent_responses,
|
649 |
+
}
|
650 |
+
|
651 |
+
else: # mode == "summary" (default)
|
652 |
+
# Get recent data (last 5 calls) with essential info only
|
653 |
+
recent_data = []
|
654 |
+
for item in monitored_data[:5]: # Only last 5 calls
|
655 |
+
recent_data.append(
|
656 |
+
{
|
657 |
+
"timestamp": item["called_at"],
|
658 |
+
"success": item.get("is_successful", False),
|
659 |
+
"error": (
|
660 |
+
item.get("error_message")
|
661 |
+
if not item.get("is_successful")
|
662 |
+
else None
|
663 |
+
),
|
664 |
+
"response_preview": (
|
665 |
+
str(item.get("response_data", ""))[:100] + "..."
|
666 |
+
if item.get("response_data")
|
667 |
+
else None
|
668 |
+
),
|
669 |
+
}
|
670 |
+
)
|
671 |
+
|
672 |
+
return {
|
673 |
+
"success": True,
|
674 |
+
"config_name": config.get("name", "Unknown"),
|
675 |
+
"summary": summary,
|
676 |
+
"recent_calls": recent_data,
|
677 |
+
"full_data_available": len(monitored_data),
|
678 |
+
"monitoring_details": {
|
679 |
+
"interval_minutes": config.get("schedule_interval_minutes"),
|
680 |
+
"is_finished": is_finished,
|
681 |
+
},
|
682 |
+
}
|
683 |
except Exception as e:
|
684 |
return {
|
685 |
"success": False,
|
|
|
720 |
config_id=activate_monitoring_response.get("config_id"),
|
721 |
mcp_api_key="your_api_key",
|
722 |
)
|
723 |
+
print(json.dumps(response, indent=2, default=str))
|
main.py
CHANGED
@@ -1,6 +1,10 @@
|
|
1 |
import gradio as gr
|
2 |
from api_client import call_api
|
3 |
-
from api_monitor import
|
|
|
|
|
|
|
|
|
4 |
import json
|
5 |
|
6 |
|
@@ -125,10 +129,42 @@ scheduler_tab = gr.Interface(
|
|
125 |
],
|
126 |
)
|
127 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
# Create tabbed interface
|
129 |
demo = gr.TabbedInterface(
|
130 |
-
[validation_tab, scheduler_tab],
|
131 |
-
["Validate & Store", "Activate Scheduler"],
|
132 |
title="MCP API Monitoring System",
|
133 |
)
|
134 |
|
|
|
1 |
import gradio as gr
|
2 |
from api_client import call_api
|
3 |
+
from api_monitor import (
|
4 |
+
validate_api_configuration,
|
5 |
+
activate_monitoring,
|
6 |
+
retrieve_monitored_data,
|
7 |
+
)
|
8 |
import json
|
9 |
|
10 |
|
|
|
129 |
],
|
130 |
)
|
131 |
|
132 |
+
# Retrieve Data Tab
|
133 |
+
retrieve_tab = gr.Interface(
|
134 |
+
fn=retrieve_monitored_data,
|
135 |
+
inputs=[
|
136 |
+
gr.Number(label="Config ID", value=None),
|
137 |
+
gr.Textbox(
|
138 |
+
label="MCP API Key", placeholder="Enter your MCP API key", type="password"
|
139 |
+
),
|
140 |
+
gr.Dropdown(
|
141 |
+
choices=["summary", "details", "full"],
|
142 |
+
label="Data Mode",
|
143 |
+
value="summary",
|
144 |
+
info="summary: LLM-optimized | details: full responses, minimal metadata | full: everything",
|
145 |
+
),
|
146 |
+
],
|
147 |
+
outputs=gr.JSON(label="Monitoring Progress & Data"),
|
148 |
+
title="Retrieve Monitoring Data",
|
149 |
+
description="STEP 3: Check the progress and retrieve data from your active monitoring configurations. Use the Config ID from the validation step. Three modes: 'summary' (LLM-optimized), 'details' (full responses), 'full' (complete debug info).",
|
150 |
+
flagging_mode="manual",
|
151 |
+
flagging_options=[
|
152 |
+
"Config Not Found",
|
153 |
+
"Invalid API Key",
|
154 |
+
"No Data Available",
|
155 |
+
"Other",
|
156 |
+
],
|
157 |
+
examples=[
|
158 |
+
[123456789, "test_mcp_key_123", "summary"],
|
159 |
+
[987654321, "test_mcp_key_456", "details"],
|
160 |
+
[456789123, "test_mcp_key_789", "full"],
|
161 |
+
],
|
162 |
+
)
|
163 |
+
|
164 |
# Create tabbed interface
|
165 |
demo = gr.TabbedInterface(
|
166 |
+
[validation_tab, scheduler_tab, retrieve_tab],
|
167 |
+
["Validate & Store", "Activate Scheduler", "Retrieve Data"],
|
168 |
title="MCP API Monitoring System",
|
169 |
)
|
170 |
|