Datasourceforcryptocurrency-2 / backend /routers /real_data_api_unified_hf.py
Your Name
feat: UI improvements and error suppression - Enhanced dashboard and market pages with improved header buttons, logo, and currency symbol display - Stopped animated ticker - Removed pie chart legends - Added error suppressor for external service errors (SSE, Permissions-Policy warnings) - Improved header button prominence and icon appearance - Enhanced logo with glow effects and better design - Fixed currency symbol visibility in market tables
8b7b267
#!/usr/bin/env python3
"""
Real Data API Router - UNIFIED HUGGINGFACE ONLY
=================================================
✅ تمام داده‌ها از HuggingFace Space
✅ بدون WebSocket (فقط HTTP REST API)
✅ بدون استفاده مستقیم از CoinMarketCap, NewsAPI, etc.
✅ تمام درخواست‌ها از طریق HuggingFaceUnifiedClient
Reference: crypto_resources_unified_2025-11-11.json
"""
from fastapi import APIRouter, HTTPException, Query, Body
from fastapi.responses import JSONResponse
from typing import Optional, List, Dict, Any
from datetime import datetime
from pydantic import BaseModel
import logging
# Import ONLY HuggingFace Unified Client
from backend.services.hf_unified_client import get_hf_client
logger = logging.getLogger(__name__)
router = APIRouter(tags=["Unified HuggingFace API"])
# Get singleton HF client
hf_client = get_hf_client()
# ============================================================================
# Pydantic Models
# ============================================================================
class PredictRequest(BaseModel):
"""Model prediction request"""
symbol: str
context: Optional[str] = None
params: Optional[Dict[str, Any]] = None
class SentimentRequest(BaseModel):
"""Sentiment analysis request"""
text: str
mode: Optional[str] = "crypto"
# ============================================================================
# Market Data Endpoints - از HuggingFace فقط
# ============================================================================
@router.get("/api/market")
async def get_market_snapshot(
limit: int = Query(100, description="Number of symbols"),
symbols: Optional[str] = Query(None, description="Comma-separated symbols (e.g., BTC,ETH)")
):
"""
دریافت داده‌های بازار از HuggingFace Space
✅ فقط از HuggingFace
❌ بدون CoinMarketCap
❌ بدون API های دیگر
"""
try:
symbol_list = None
if symbols:
symbol_list = [s.strip() for s in symbols.split(',')]
result = await hf_client.get_market_prices(
symbols=symbol_list,
limit=limit
)
if not result.get("success"):
raise HTTPException(
status_code=503,
detail=result.get("error", "HuggingFace Space returned error")
)
logger.info(f"✅ Market data from HF: {len(result.get('data', []))} symbols")
return result
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Market data failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch market data from HuggingFace: {str(e)}"
)
@router.get("/api/market/history")
async def get_market_history(
symbol: str = Query(..., description="Symbol (e.g., BTCUSDT)"),
timeframe: str = Query("1h", description="Timeframe (1m, 5m, 15m, 1h, 4h, 1d)"),
limit: int = Query(1000, description="Number of candles")
):
"""
دریافت داده‌های OHLCV از HuggingFace Space
✅ فقط از HuggingFace
❌ بدون CoinMarketCap یا Binance
"""
try:
result = await hf_client.get_market_history(
symbol=symbol,
timeframe=timeframe,
limit=limit
)
if not result.get("success"):
raise HTTPException(
status_code=404,
detail=result.get("error", "OHLCV data not available")
)
logger.info(f"✅ OHLCV from HF: {symbol} {timeframe} ({len(result.get('data', []))} candles)")
return result
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ OHLCV data failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch OHLCV data from HuggingFace: {str(e)}"
)
@router.get("/api/market/pairs")
async def get_trading_pairs():
"""
دریافت لیست جفت‌های معاملاتی
در صورت عدم وجود endpoint در HuggingFace، از اطلاعات market data استفاده می‌شود
"""
try:
# Try to get pairs from HF
# If not available, derive from market data
market_data = await hf_client.get_market_prices(limit=50)
if not market_data.get("success"):
raise HTTPException(status_code=503, detail="Failed to fetch market data")
pairs = []
for item in market_data.get("data", []):
symbol = item.get("symbol", "")
if symbol:
pairs.append({
"pair": f"{symbol}/USDT",
"base": symbol,
"quote": "USDT",
"tick_size": 0.01,
"min_qty": 0.001
})
return {
"success": True,
"pairs": pairs,
"meta": {
"cache_ttl_seconds": 300,
"generated_at": datetime.utcnow().isoformat(),
"source": "hf_engine"
}
}
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Trading pairs failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch trading pairs: {str(e)}"
)
@router.get("/api/market/tickers")
async def get_tickers(
limit: int = Query(100, description="Number of tickers"),
sort: str = Query("market_cap", description="Sort by: market_cap, volume, change")
):
"""
دریافت tickers مرتب‌شده از HuggingFace
"""
try:
market_data = await hf_client.get_market_prices(limit=limit)
if not market_data.get("success"):
raise HTTPException(status_code=503, detail="Failed to fetch market data")
tickers = []
for item in market_data.get("data", []):
tickers.append({
"symbol": item.get("symbol", ""),
"price": item.get("price", 0),
"change_24h": item.get("change_24h", 0),
"volume_24h": item.get("volume_24h", 0),
"market_cap": item.get("market_cap", 0)
})
# Sort tickers
if sort == "volume":
tickers.sort(key=lambda x: x.get("volume_24h", 0), reverse=True)
elif sort == "change":
tickers.sort(key=lambda x: x.get("change_24h", 0), reverse=True)
elif sort == "market_cap":
tickers.sort(key=lambda x: x.get("market_cap", 0), reverse=True)
return {
"success": True,
"tickers": tickers,
"meta": {
"cache_ttl_seconds": 60,
"generated_at": datetime.utcnow().isoformat(),
"source": "hf_engine",
"sort": sort
}
}
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Tickers failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch tickers: {str(e)}"
)
# ============================================================================
# Sentiment Analysis - از HuggingFace فقط
# ============================================================================
@router.post("/api/sentiment/analyze")
async def analyze_sentiment(request: SentimentRequest):
"""
تحلیل احساسات با مدل‌های AI در HuggingFace
✅ فقط از HuggingFace AI Models
❌ بدون مدل‌های محلی
"""
try:
result = await hf_client.analyze_sentiment(text=request.text)
if not result.get("success"):
raise HTTPException(
status_code=500,
detail=result.get("error", "Sentiment analysis failed")
)
logger.info(f"✅ Sentiment from HF: {result.get('data', {}).get('sentiment')}")
return result
except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Sentiment analysis failed: {e}")
raise HTTPException(
status_code=500,
detail=f"Failed to analyze sentiment: {str(e)}"
)
# ============================================================================
# News - از HuggingFace فقط
# ============================================================================
@router.get("/api/news")
async def get_news(
limit: int = Query(20, description="Number of articles"),
source: Optional[str] = Query(None, description="Filter by source")
):
"""
دریافت اخبار از HuggingFace Space
✅ فقط از HuggingFace
❌ بدون NewsAPI مستقیم
"""
try:
result = await hf_client.get_news(limit=limit, source=source)
logger.info(f"✅ News from HF: {len(result.get('articles', []))} articles")
return result
except Exception as e:
logger.error(f"❌ News failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch news from HuggingFace: {str(e)}"
)
@router.get("/api/news/latest")
async def get_latest_news(
symbol: str = Query("BTC", description="Crypto symbol"),
limit: int = Query(10, description="Number of articles")
):
"""
دریافت آخرین اخبار برای سمبل خاص
"""
try:
# HF news endpoint filters by source, we return all and user can filter client-side
result = await hf_client.get_news(limit=limit)
return {
"success": True,
"symbol": symbol,
"news": result.get("articles", []),
"meta": {
"total": len(result.get("articles", [])),
"source": "hf_engine",
"timestamp": datetime.utcnow().isoformat()
}
}
except Exception as e:
logger.error(f"❌ Latest news failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch latest news: {str(e)}"
)
# ============================================================================
# Blockchain Data - از HuggingFace فقط
# ============================================================================
@router.get("/api/blockchain/gas")
async def get_gas_prices(
chain: str = Query("ethereum", description="Blockchain network")
):
"""
دریافت قیمت گس از HuggingFace Space
✅ فقط از HuggingFace
❌ بدون Etherscan/BSCScan مستقیم
"""
try:
result = await hf_client.get_blockchain_gas_prices(chain=chain)
logger.info(f"✅ Gas prices from HF: {chain}")
return result
except Exception as e:
logger.error(f"❌ Gas prices failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch gas prices from HuggingFace: {str(e)}"
)
@router.get("/api/blockchain/stats")
async def get_blockchain_stats(
chain: str = Query("ethereum", description="Blockchain network"),
hours: int = Query(24, description="Time window in hours")
):
"""
دریافت آمار بلاکچین از HuggingFace Space
"""
try:
result = await hf_client.get_blockchain_stats(chain=chain, hours=hours)
logger.info(f"✅ Blockchain stats from HF: {chain}")
return result
except Exception as e:
logger.error(f"❌ Blockchain stats failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch blockchain stats from HuggingFace: {str(e)}"
)
# ============================================================================
# Whale Tracking - از HuggingFace فقط
# ============================================================================
@router.get("/api/whales/transactions")
async def get_whale_transactions(
limit: int = Query(50, description="Number of transactions"),
chain: Optional[str] = Query(None, description="Filter by blockchain"),
min_amount_usd: float = Query(100000, description="Minimum amount in USD")
):
"""
دریافت تراکنش‌های نهنگ‌ها از HuggingFace Space
"""
try:
result = await hf_client.get_whale_transactions(
limit=limit,
chain=chain,
min_amount_usd=min_amount_usd
)
logger.info(f"✅ Whale transactions from HF: {len(result.get('transactions', []))}")
return result
except Exception as e:
logger.error(f"❌ Whale transactions failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch whale transactions from HuggingFace: {str(e)}"
)
@router.get("/api/whales/stats")
async def get_whale_stats(
hours: int = Query(24, description="Time window in hours")
):
"""
دریافت آمار نهنگ‌ها از HuggingFace Space
"""
try:
result = await hf_client.get_whale_stats(hours=hours)
logger.info(f"✅ Whale stats from HF")
return result
except Exception as e:
logger.error(f"❌ Whale stats failed: {e}")
raise HTTPException(
status_code=503,
detail=f"Failed to fetch whale stats from HuggingFace: {str(e)}"
)
# ============================================================================
# Health & Status
# ============================================================================
@router.get("/api/health")
async def health_check():
"""
بررسی سلامت سیستم با چک HuggingFace Space
"""
try:
hf_health = await hf_client.health_check()
return {
"status": "healthy" if hf_health.get("success") else "degraded",
"timestamp": datetime.utcnow().isoformat(),
"huggingface_space": hf_health,
"checks": {
"hf_space_connection": hf_health.get("success", False),
"hf_database": hf_health.get("database", "unknown"),
"hf_ai_models": hf_health.get("ai_models", {})
}
}
except Exception as e:
logger.error(f"❌ Health check failed: {e}")
return {
"status": "unhealthy",
"timestamp": datetime.utcnow().isoformat(),
"error": str(e),
"checks": {
"hf_space_connection": False
}
}
@router.get("/api/status")
async def get_system_status():
"""
دریافت وضعیت کلی سیستم
"""
try:
hf_status = await hf_client.get_system_status()
return {
"status": "operational",
"timestamp": datetime.utcnow().isoformat(),
"mode": "UNIFIED_HUGGINGFACE_ONLY",
"mock_data": False,
"direct_api_calls": False,
"all_via_huggingface": True,
"huggingface_space": hf_status,
"version": "3.0.0-unified-hf"
}
except Exception as e:
logger.error(f"❌ Status check failed: {e}")
return {
"status": "degraded",
"timestamp": datetime.utcnow().isoformat(),
"error": str(e),
"mode": "UNIFIED_HUGGINGFACE_ONLY"
}
@router.get("/api/providers")
async def get_providers():
"""
لیست ارائه‌دهندگان - فقط HuggingFace
"""
providers = [
{
"id": "huggingface_space",
"name": "HuggingFace Space",
"category": "all",
"status": "active",
"capabilities": [
"market_data",
"ohlcv",
"sentiment_analysis",
"news",
"blockchain_stats",
"whale_tracking",
"ai_models"
],
"has_api_token": True,
"endpoint": hf_client.base_url
}
]
return {
"success": True,
"providers": providers,
"total": len(providers),
"meta": {
"timestamp": datetime.utcnow().isoformat(),
"unified_source": "huggingface_space",
"no_direct_api_calls": True
}
}
# Export router
__all__ = ["router"]