| |
| """ |
| HuggingFace Space Crypto Resources API Client Service |
| سرویس کلاینت برای API منابع کریپتو در HuggingFace Space |
| |
| This service provides access to the external HF Space Crypto Resources API: |
| https://really-amin-crypto-api-clean.hf.space |
| |
| Features: |
| - Market data (top coins, trending) |
| - Global market overview |
| - Fear & Greed Index |
| - Resource database (281 resources in 12 categories) |
| """ |
|
|
| import httpx |
| import asyncio |
| import logging |
| from typing import Dict, Any, List, Optional |
| from datetime import datetime, timezone |
| from functools import lru_cache |
|
|
| logger = logging.getLogger(__name__) |
|
|
| |
| HF_CRYPTO_API_BASE_URL = "https://really-amin-crypto-api-clean.hf.space" |
|
|
| |
| _resources_cache: Dict[str, Any] = {} |
| _cache_timestamp: Optional[datetime] = None |
| CACHE_TTL_SECONDS = 300 |
|
|
|
|
| class HFSpaceCryptoService: |
| """ |
| Service for accessing HuggingFace Space Crypto Resources API |
| Follows project patterns with proper error handling and logging |
| """ |
| |
| def __init__(self, timeout: int = 15): |
| self.base_url = HF_CRYPTO_API_BASE_URL |
| self.timeout = timeout |
| self._client: Optional[httpx.AsyncClient] = None |
| |
| async def _get_client(self) -> httpx.AsyncClient: |
| """Get or create async HTTP client""" |
| if self._client is None or self._client.is_closed: |
| self._client = httpx.AsyncClient(timeout=self.timeout) |
| return self._client |
| |
| async def close(self): |
| """Close the HTTP client""" |
| if self._client and not self._client.is_closed: |
| await self._client.aclose() |
| |
| async def _request(self, endpoint: str, params: Dict = None) -> Dict[str, Any]: |
| """ |
| Make async request to HF Space API with proper error handling |
| |
| Returns standardized response format matching project patterns |
| """ |
| provider = "HFSpaceCryptoAPI" |
| start_time = datetime.now(timezone.utc) |
| |
| try: |
| client = await self._get_client() |
| url = f"{self.base_url}{endpoint}" |
| |
| response = await client.get(url, params=params) |
| response.raise_for_status() |
| |
| data = response.json() |
| response_time_ms = (datetime.now(timezone.utc) - start_time).total_seconds() * 1000 |
| |
| logger.info(f"✅ {provider} - {endpoint} - {response_time_ms:.0f}ms") |
| |
| return { |
| "provider": provider, |
| "endpoint": endpoint, |
| "data": data, |
| "timestamp": datetime.now(timezone.utc).isoformat(), |
| "response_time_ms": response_time_ms, |
| "success": True, |
| "error": None |
| } |
| |
| except httpx.HTTPStatusError as e: |
| logger.error(f"❌ {provider} - {endpoint} - HTTP {e.response.status_code}") |
| return { |
| "provider": provider, |
| "endpoint": endpoint, |
| "data": None, |
| "timestamp": datetime.now(timezone.utc).isoformat(), |
| "success": False, |
| "error": f"HTTP {e.response.status_code}", |
| "error_type": "http_error" |
| } |
| except httpx.TimeoutException: |
| logger.error(f"❌ {provider} - {endpoint} - Timeout") |
| return { |
| "provider": provider, |
| "endpoint": endpoint, |
| "data": None, |
| "timestamp": datetime.now(timezone.utc).isoformat(), |
| "success": False, |
| "error": "Request timeout", |
| "error_type": "timeout" |
| } |
| except Exception as e: |
| logger.error(f"❌ {provider} - {endpoint} - {str(e)}") |
| return { |
| "provider": provider, |
| "endpoint": endpoint, |
| "data": None, |
| "timestamp": datetime.now(timezone.utc).isoformat(), |
| "success": False, |
| "error": str(e), |
| "error_type": "exception" |
| } |
| |
| |
| |
| async def get_top_coins(self, limit: int = 50) -> Dict[str, Any]: |
| """ |
| Get top coins by market cap |
| دریافت برترین ارزها بر اساس مارکت کپ |
| """ |
| return await self._request("/api/coins/top", params={"limit": limit}) |
| |
| async def get_trending(self) -> Dict[str, Any]: |
| """ |
| Get trending coins |
| دریافت ارزهای ترند |
| """ |
| return await self._request("/api/trending") |
| |
| async def get_market_overview(self) -> Dict[str, Any]: |
| """ |
| Get global market overview |
| خلاصه کلی بازار |
| """ |
| return await self._request("/api/market") |
| |
| |
| |
| async def get_global_sentiment(self, timeframe: str = "1D") -> Dict[str, Any]: |
| """ |
| Get Fear & Greed Index |
| شاخص ترس و طمع |
| """ |
| return await self._request("/api/sentiment/global", params={"timeframe": timeframe}) |
| |
| async def get_asset_sentiment(self, symbol: str) -> Dict[str, Any]: |
| """ |
| Get sentiment for specific asset |
| احساسات یک ارز خاص |
| """ |
| return await self._request(f"/api/sentiment/asset/{symbol}") |
| |
| |
| |
| async def get_resources_stats(self) -> Dict[str, Any]: |
| """ |
| Get resources database statistics |
| آمار منابع |
| """ |
| return await self._request("/api/resources/stats") |
| |
| async def get_categories(self) -> Dict[str, Any]: |
| """ |
| Get list of resource categories |
| لیست دستهبندیها |
| """ |
| return await self._request("/api/categories") |
| |
| async def get_resources_by_category(self, category: str) -> Dict[str, Any]: |
| """ |
| Get resources for a specific category |
| منابع یک دسته خاص |
| |
| Categories: rpc_nodes, block_explorers, market_data_apis, news_apis, |
| sentiment_apis, onchain_analytics_apis, whale_tracking_apis, |
| hf_resources, free_http_endpoints, cors_proxies |
| """ |
| return await self._request(f"/api/resources/category/{category}") |
| |
| async def get_all_resources(self) -> Dict[str, Any]: |
| """ |
| Get all resources list |
| لیست همه منابع |
| """ |
| return await self._request("/api/resources/list") |
| |
| |
| |
| async def health_check(self) -> Dict[str, Any]: |
| """Check API health status""" |
| return await self._request("/health") |
| |
| async def get_providers_status(self) -> Dict[str, Any]: |
| """Get data providers status""" |
| return await self._request("/api/providers") |
| |
| async def get_system_status(self) -> Dict[str, Any]: |
| """Get system status""" |
| return await self._request("/api/status") |
| |
| |
| |
| async def get_fear_greed_index(self) -> int: |
| """ |
| Get current Fear & Greed Index value |
| |
| Returns: |
| int: Fear & Greed Index (0-100) |
| """ |
| result = await self.get_global_sentiment() |
| if result["success"] and result["data"]: |
| return result["data"].get("fear_greed_index", 50) |
| return 50 |
| |
| async def get_btc_price(self) -> float: |
| """ |
| Get current Bitcoin price |
| |
| Returns: |
| float: BTC price in USD |
| """ |
| result = await self.get_top_coins(limit=1) |
| if result["success"] and result["data"]: |
| coins = result["data"].get("coins", []) |
| if coins: |
| return coins[0].get("current_price", 0) |
| return 0 |
| |
| async def get_total_market_cap(self) -> float: |
| """ |
| Get total crypto market cap |
| |
| Returns: |
| float: Total market cap in USD |
| """ |
| result = await self.get_market_overview() |
| if result["success"] and result["data"]: |
| return result["data"].get("total_market_cap", 0) |
| return 0 |
|
|
|
|
| |
|
|
| _service_instance: Optional[HFSpaceCryptoService] = None |
|
|
|
|
| def get_hf_space_crypto_service() -> HFSpaceCryptoService: |
| """Get singleton instance of HF Space Crypto Service""" |
| global _service_instance |
| if _service_instance is None: |
| _service_instance = HFSpaceCryptoService() |
| return _service_instance |
|
|
|
|
| |
|
|
| async def fetch_hf_space_top_coins(limit: int = 50) -> Dict[str, Any]: |
| """Fetch top coins from HF Space API""" |
| service = get_hf_space_crypto_service() |
| return await service.get_top_coins(limit) |
|
|
|
|
| async def fetch_hf_space_trending() -> Dict[str, Any]: |
| """Fetch trending coins from HF Space API""" |
| service = get_hf_space_crypto_service() |
| return await service.get_trending() |
|
|
|
|
| async def fetch_hf_space_market_overview() -> Dict[str, Any]: |
| """Fetch market overview from HF Space API""" |
| service = get_hf_space_crypto_service() |
| return await service.get_market_overview() |
|
|
|
|
| async def fetch_hf_space_sentiment() -> Dict[str, Any]: |
| """Fetch global sentiment from HF Space API""" |
| service = get_hf_space_crypto_service() |
| return await service.get_global_sentiment() |
|
|
|
|
| async def fetch_hf_space_resources(category: Optional[str] = None) -> Dict[str, Any]: |
| """Fetch resources from HF Space API""" |
| service = get_hf_space_crypto_service() |
| if category: |
| return await service.get_resources_by_category(category) |
| return await service.get_resources_stats() |
|
|
|
|
| |
|
|
| if __name__ == "__main__": |
| async def main(): |
| service = get_hf_space_crypto_service() |
| |
| print("=" * 60) |
| print("Testing HF Space Crypto Service") |
| print("=" * 60) |
| |
| |
| print("\n1. Health Check:") |
| result = await service.health_check() |
| print(f" Success: {result['success']}") |
| if result['success']: |
| print(f" Status: {result['data'].get('status')}") |
| |
| |
| print("\n2. Top 3 Coins:") |
| result = await service.get_top_coins(limit=3) |
| if result['success']: |
| for coin in result['data'].get('coins', []): |
| print(f" {coin['name']}: ${coin['current_price']:,.2f}") |
| |
| |
| print("\n3. Fear & Greed Index:") |
| fgi = await service.get_fear_greed_index() |
| print(f" Index: {fgi}") |
| |
| |
| print("\n4. Resources Stats:") |
| result = await service.get_resources_stats() |
| if result['success']: |
| print(f" Total: {result['data'].get('total_resources')}") |
| print(f" Categories: {result['data'].get('total_categories')}") |
| |
| await service.close() |
| print("\n" + "=" * 60) |
| print("Tests completed!") |
| |
| asyncio.run(main()) |
|
|