Spaces:
Sleeping
Sleeping
| """Simple FastAPI server for testing HF integration""" | |
| import asyncio | |
| from fastapi import FastAPI | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import FileResponse, JSONResponse | |
| from fastapi.staticfiles import StaticFiles | |
| import uvicorn | |
| # Create FastAPI app | |
| app = FastAPI(title="Crypto API Monitor - Simple", version="1.0.0") | |
| # CORS | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Include HF router | |
| try: | |
| from backend.routers import hf_connect | |
| app.include_router(hf_connect.router) | |
| print("β HF router loaded") | |
| except Exception as e: | |
| print(f"β HF router failed: {e}") | |
| # Background task for HF registry | |
| async def startup_hf(): | |
| try: | |
| from backend.services.hf_registry import periodic_refresh | |
| asyncio.create_task(periodic_refresh()) | |
| print("β HF background refresh started") | |
| except Exception as e: | |
| print(f"β HF background refresh failed: {e}") | |
| # Health endpoint | |
| async def health(): | |
| return {"status": "healthy", "service": "crypto-api-monitor"} | |
| async def api_health(): | |
| return {"status": "healthy", "service": "crypto-api-monitor-api"} | |
| # Serve static files | |
| async def root(): | |
| return FileResponse("index.html") | |
| async def index(): | |
| return FileResponse("index.html") | |
| async def hf_console(): | |
| return FileResponse("hf_console.html") | |
| # Mock API endpoints for dashboard | |
| async def api_status(): | |
| """Mock status endpoint""" | |
| return { | |
| "total_providers": 9, | |
| "online": 7, | |
| "degraded": 1, | |
| "offline": 1, | |
| "avg_response_time_ms": 245, | |
| "total_requests_hour": 156, | |
| "total_failures_hour": 3, | |
| "system_health": "healthy", | |
| "timestamp": "2025-11-11T01:30:00Z" | |
| } | |
| async def api_categories(): | |
| """Mock categories endpoint""" | |
| return [ | |
| { | |
| "name": "market_data", | |
| "total_sources": 3, | |
| "online_sources": 3, | |
| "avg_response_time_ms": 180, | |
| "rate_limited_count": 0, | |
| "last_updated": "2025-11-11T01:30:00Z", | |
| "status": "online" | |
| }, | |
| { | |
| "name": "blockchain_explorers", | |
| "total_sources": 3, | |
| "online_sources": 2, | |
| "avg_response_time_ms": 320, | |
| "rate_limited_count": 1, | |
| "last_updated": "2025-11-11T01:29:00Z", | |
| "status": "online" | |
| }, | |
| { | |
| "name": "news", | |
| "total_sources": 2, | |
| "online_sources": 2, | |
| "avg_response_time_ms": 450, | |
| "rate_limited_count": 0, | |
| "last_updated": "2025-11-11T01:28:00Z", | |
| "status": "online" | |
| }, | |
| { | |
| "name": "sentiment", | |
| "total_sources": 1, | |
| "online_sources": 1, | |
| "avg_response_time_ms": 200, | |
| "rate_limited_count": 0, | |
| "last_updated": "2025-11-11T01:30:00Z", | |
| "status": "online" | |
| } | |
| ] | |
| async def api_providers(): | |
| """Mock providers endpoint""" | |
| return [ | |
| { | |
| "id": 1, | |
| "name": "CoinGecko", | |
| "category": "market_data", | |
| "status": "online", | |
| "response_time_ms": 150, | |
| "last_fetch": "2025-11-11T01:30:00Z", | |
| "has_key": False, | |
| "rate_limit": None | |
| }, | |
| { | |
| "id": 2, | |
| "name": "Binance", | |
| "category": "market_data", | |
| "status": "online", | |
| "response_time_ms": 120, | |
| "last_fetch": "2025-11-11T01:30:00Z", | |
| "has_key": False, | |
| "rate_limit": None | |
| }, | |
| { | |
| "id": 3, | |
| "name": "Alternative.me", | |
| "category": "sentiment", | |
| "status": "online", | |
| "response_time_ms": 200, | |
| "last_fetch": "2025-11-11T01:29:00Z", | |
| "has_key": False, | |
| "rate_limit": None | |
| }, | |
| { | |
| "id": 4, | |
| "name": "Etherscan", | |
| "category": "blockchain_explorers", | |
| "status": "online", | |
| "response_time_ms": 280, | |
| "last_fetch": "2025-11-11T01:29:30Z", | |
| "has_key": True, | |
| "rate_limit": {"used": 45, "total": 100} | |
| }, | |
| { | |
| "id": 5, | |
| "name": "CryptoPanic", | |
| "category": "news", | |
| "status": "online", | |
| "response_time_ms": 380, | |
| "last_fetch": "2025-11-11T01:28:00Z", | |
| "has_key": False, | |
| "rate_limit": None | |
| } | |
| ] | |
| async def api_health_history(hours: int = 24): | |
| """Mock health history chart data""" | |
| import random | |
| from datetime import datetime, timedelta | |
| now = datetime.now() | |
| timestamps = [(now - timedelta(hours=i)).isoformat() for i in range(23, -1, -1)] | |
| return { | |
| "timestamps": timestamps, | |
| "success_rate": [random.randint(85, 100) for _ in range(24)] | |
| } | |
| async def api_compliance(days: int = 7): | |
| """Mock compliance chart data""" | |
| import random | |
| from datetime import datetime, timedelta | |
| now = datetime.now() | |
| dates = [(now - timedelta(days=i)).strftime("%a") for i in range(6, -1, -1)] | |
| return { | |
| "dates": dates, | |
| "compliance_percentage": [random.randint(90, 100) for _ in range(7)] | |
| } | |
| async def api_logs(): | |
| """Mock logs endpoint""" | |
| return [ | |
| { | |
| "timestamp": "2025-11-11T01:30:00Z", | |
| "provider": "CoinGecko", | |
| "endpoint": "/api/v3/ping", | |
| "status": "success", | |
| "response_time_ms": 150, | |
| "http_code": 200, | |
| "error_message": None | |
| }, | |
| { | |
| "timestamp": "2025-11-11T01:29:30Z", | |
| "provider": "Binance", | |
| "endpoint": "/api/v3/klines", | |
| "status": "success", | |
| "response_time_ms": 120, | |
| "http_code": 200, | |
| "error_message": None | |
| }, | |
| { | |
| "timestamp": "2025-11-11T01:29:00Z", | |
| "provider": "Alternative.me", | |
| "endpoint": "/fng/", | |
| "status": "success", | |
| "response_time_ms": 200, | |
| "http_code": 200, | |
| "error_message": None | |
| } | |
| ] | |
| async def api_rate_limits(): | |
| """Mock rate limits endpoint""" | |
| return [ | |
| { | |
| "provider": "CoinGecko", | |
| "limit_type": "per_minute", | |
| "limit_value": 50, | |
| "current_usage": 12, | |
| "percentage": 24.0, | |
| "reset_in_seconds": 45 | |
| }, | |
| { | |
| "provider": "Etherscan", | |
| "limit_type": "per_second", | |
| "limit_value": 5, | |
| "current_usage": 3, | |
| "percentage": 60.0, | |
| "reset_in_seconds": 1 | |
| } | |
| ] | |
| async def api_rate_limit_history(hours: int = 24): | |
| """Mock rate limit history chart data""" | |
| import random | |
| from datetime import datetime, timedelta | |
| now = datetime.now() | |
| timestamps = [(now - timedelta(hours=i)).strftime("%H:00") for i in range(23, -1, -1)] | |
| return { | |
| "timestamps": timestamps, | |
| "providers": { | |
| "CoinGecko": [random.randint(10, 40) for _ in range(24)], | |
| "Etherscan": [random.randint(40, 80) for _ in range(24)] | |
| } | |
| } | |
| async def api_schedule(): | |
| """Mock schedule endpoint""" | |
| return [ | |
| { | |
| "provider": "CoinGecko", | |
| "category": "market_data", | |
| "schedule": "every_1_min", | |
| "last_run": "2025-11-11T01:30:00Z", | |
| "next_run": "2025-11-11T01:31:00Z", | |
| "on_time_percentage": 98.5, | |
| "status": "active" | |
| }, | |
| { | |
| "provider": "Binance", | |
| "category": "market_data", | |
| "schedule": "every_1_min", | |
| "last_run": "2025-11-11T01:30:00Z", | |
| "next_run": "2025-11-11T01:31:00Z", | |
| "on_time_percentage": 99.2, | |
| "status": "active" | |
| }, | |
| { | |
| "provider": "Alternative.me", | |
| "category": "sentiment", | |
| "schedule": "every_15_min", | |
| "last_run": "2025-11-11T01:15:00Z", | |
| "next_run": "2025-11-11T01:30:00Z", | |
| "on_time_percentage": 97.8, | |
| "status": "active" | |
| } | |
| ] | |
| async def api_freshness(): | |
| """Mock freshness endpoint""" | |
| return [ | |
| { | |
| "provider": "CoinGecko", | |
| "category": "market_data", | |
| "fetch_time": "2025-11-11T01:30:00Z", | |
| "data_timestamp": "2025-11-11T01:29:55Z", | |
| "staleness_minutes": 0.08, | |
| "ttl_minutes": 5, | |
| "status": "fresh" | |
| }, | |
| { | |
| "provider": "Binance", | |
| "category": "market_data", | |
| "fetch_time": "2025-11-11T01:30:00Z", | |
| "data_timestamp": "2025-11-11T01:29:58Z", | |
| "staleness_minutes": 0.03, | |
| "ttl_minutes": 5, | |
| "status": "fresh" | |
| } | |
| ] | |
| async def api_failures(): | |
| """Mock failures endpoint""" | |
| return { | |
| "recent_failures": [ | |
| { | |
| "timestamp": "2025-11-11T01:25:00Z", | |
| "provider": "NewsAPI", | |
| "error_type": "timeout", | |
| "error_message": "Request timeout after 10s", | |
| "retry_attempted": True, | |
| "retry_result": "success" | |
| } | |
| ], | |
| "error_type_distribution": { | |
| "timeout": 2, | |
| "rate_limit": 1, | |
| "connection_error": 0 | |
| }, | |
| "top_failing_providers": [ | |
| {"provider": "NewsAPI", "failure_count": 2}, | |
| {"provider": "TronScan", "failure_count": 1} | |
| ], | |
| "remediation_suggestions": [ | |
| { | |
| "provider": "NewsAPI", | |
| "issue": "Frequent timeouts", | |
| "suggestion": "Consider increasing timeout threshold or checking network connectivity" | |
| } | |
| ] | |
| } | |
| async def api_freshness_history(hours: int = 24): | |
| """Mock freshness history chart data""" | |
| import random | |
| from datetime import datetime, timedelta | |
| now = datetime.now() | |
| timestamps = [(now - timedelta(hours=i)).strftime("%H:00") for i in range(23, -1, -1)] | |
| return { | |
| "timestamps": timestamps, | |
| "providers": { | |
| "CoinGecko": [random.uniform(0.1, 2.0) for _ in range(24)], | |
| "Binance": [random.uniform(0.05, 1.5) for _ in range(24)] | |
| } | |
| } | |
| async def api_config_keys(): | |
| """Mock API keys config""" | |
| return [ | |
| { | |
| "provider": "Etherscan", | |
| "key_masked": "YourApiKeyToken...abc123", | |
| "expires_at": None, | |
| "status": "active" | |
| }, | |
| { | |
| "provider": "CoinMarketCap", | |
| "key_masked": "b54bcf4d-1bca...xyz789", | |
| "expires_at": "2025-12-31", | |
| "status": "active" | |
| } | |
| ] | |
| if __name__ == "__main__": | |
| print("=" * 70) | |
| print("π Starting Crypto API Monitor - Simple Server") | |
| print("=" * 70) | |
| print("π Server: http://localhost:7860") | |
| print("π Main Dashboard: http://localhost:7860/index.html") | |
| print("π€ HF Console: http://localhost:7860/hf_console.html") | |
| print("π API Docs: http://localhost:7860/docs") | |
| print("=" * 70) | |
| print() | |
| uvicorn.run( | |
| app, | |
| host="0.0.0.0", | |
| port=7860, | |
| log_level="info" | |
| ) | |