#!/usr/bin/env python3 """ Whale Tracking Router GET /api/whales/transactions, GET /api/whales/activity """ from fastapi import APIRouter, HTTPException, Query from fastapi.responses import JSONResponse from typing import Optional, List, Dict, Any from datetime import datetime, timezone, timedelta import logging from backend.services.provider_fallback_manager import fallback_manager from backend.services.data_resolver import get_data_resolver from backend.services.persistence_service import PersistenceService from database.db_manager import db_manager logger = logging.getLogger(__name__) router = APIRouter( prefix="/api/whales", tags=["Whale Tracking"] ) persistence_service = PersistenceService() def create_response(data: Any, source: str, attempted: List[str] = None) -> Dict[str, Any]: """Create standardized response""" return { "data": data, "meta": { "source": source, "generated_at": datetime.now(timezone.utc).isoformat(), "cache_ttl": 60, "attempted": attempted or [source] } } @router.get("/transactions") async def get_whale_transactions( limit: int = Query(50, description="Number of transactions"), chain: Optional[str] = Query(None, description="Blockchain (ethereum, bsc, tron)"), min_amount_usd: Optional[float] = Query(100000, description="Minimum amount in USD") ): """Get whale transactions""" attempted = [] # Try database first try: transactions = await persistence_service.get_whale_transactions( limit=limit, chain=chain, min_amount=min_amount_usd ) if transactions: attempted.append("database") return create_response(transactions, "database", attempted) except Exception as e: logger.warning(f"Database query failed: {e}") attempted.append("database") # Try HF Space try: resolver = await get_data_resolver() whale_data = await resolver.resolve_whale_transactions(limit=limit, chain=chain) if whale_data: attempted.append("hf") # Save to database await persistence_service.save_whale_transactions(whale_data) return create_response(whale_data, "hf", attempted) except Exception as e: logger.warning(f"HF Space unavailable: {e}") attempted.append("hf") # Fallback to external APIs try: result = await fallback_manager.fetch_with_fallback( endpoint="/whale/transactions", params={"limit": limit, "chain": chain or "ethereum"}, transform_func=lambda x: x if isinstance(x, list) else [] ) attempted.extend(result.attempted) if result.success and result.data: # Filter by min_amount filtered = [ tx for tx in result.data if tx.get("amount_usd", 0) >= min_amount_usd ] await persistence_service.save_whale_transactions(filtered) return create_response(filtered[:limit], result.source, attempted) except Exception as e: logger.error(f"External APIs failed: {e}") attempted.append("external_apis") # Return empty with attempted sources return create_response([], "none", attempted) @router.get("/activity") async def get_whale_activity( hours: int = Query(24, description="Hours to look back") ): """Get whale activity statistics""" attempted = [] # Try database try: since = datetime.now(timezone.utc) - timedelta(hours=hours) activity = await persistence_service.get_whale_activity_stats(since) if activity: attempted.append("database") return create_response(activity, "database", attempted) except Exception as e: logger.warning(f"Database query failed: {e}") attempted.append("database") # Try HF Space try: resolver = await get_data_resolver() activity = await resolver.resolve_whale_activity(hours=hours) if activity: attempted.append("hf") return create_response(activity, "hf", attempted) except Exception as e: logger.warning(f"HF Space unavailable: {e}") attempted.append("hf") # Fallback to external try: result = await fallback_manager.fetch_with_fallback( endpoint="/whale/stats", params={"hours": hours}, transform_func=lambda x: x if isinstance(x, dict) else {} ) attempted.extend(result.attempted) if result.success: return create_response(result.data, result.source, attempted) except Exception as e: logger.error(f"External APIs failed: {e}") attempted.append("external_apis") # Return default stats default_stats = { "total_transactions": 0, "total_volume_usd": 0, "top_chains": [], "period_hours": hours } return create_response(default_stats, "default", attempted)