import gradio as gr import requests import pandas as pd import plotly.graph_objects as go from huggingface_hub import InferenceClient import os # ----------------------------------------------------------------------------- # 1. CONFIGURATION & STATE # ----------------------------------------------------------------------------- # We keep a global variable to store the latest market text for the AI to read MARKET_CONTEXT = "Market data is currently loading..." def get_client(): # Tries to get the HF_TOKEN from the Space secrets, otherwise falls back to free tier token = os.getenv("HF_TOKEN") return InferenceClient(model="Qwen/Qwen2.5-VL-3B-Instruct", token=token) # ----------------------------------------------------------------------------- # 2. DATA FETCHING & PROCESSING # ----------------------------------------------------------------------------- def fetch_crypto_data(): """Fetches data from CoinGecko and returns a dict of metrics + sparklines + context string""" url = "https://api.coingecko.com/api/v3/coins/markets" params = { "vs_currency": "usd", "ids": "bitcoin,ethereum,solana,binancecoin", "order": "market_cap_desc", "per_page": 4, "page": 1, "sparkline": "true", "price_change_percentage": "24h,7d" } global MARKET_CONTEXT try: response = requests.get(url, params=params, timeout=10) data = response.json() # Build the context string for AI context_parts = [] processed_data = [] for coin in data: symbol = coin['symbol'].upper() price = coin['current_price'] chg_24 = coin.get('price_change_percentage_24h_in_currency', 0) chg_7d = coin.get('price_change_percentage_7d_in_currency', 0) mcap = coin['market_cap'] history = coin.get('sparkline_in_7d', {}).get('price', []) # Add to AI context context_parts.append(f"{symbol}: ${price}, 24h: {chg_24:.1f}%, 7d: {chg_7d:.1f}%") processed_data.append({ "name": coin['name'], "symbol": symbol, "price": price, "chg_24": chg_24, "chg_7d": chg_7d, "mcap": mcap, "history": history }) MARKET_CONTEXT = " | ".join(context_parts) return processed_data except Exception as e: MARKET_CONTEXT = "Error fetching market data." print(f"API Error: {e}") return [] # ----------------------------------------------------------------------------- # 3. UI GENERATION (HTML + PLOTS) # ----------------------------------------------------------------------------- def create_sparkline(history, chg_24): """Creates a minimalist Plotly sparkline""" color = "#00ff00" if chg_24 >= 0 else "#ff4444" fig = go.Figure() fig.add_trace(go.Scatter( y=history, mode='lines', fill='tozeroy', line=dict(color=color, width=2), fillcolor=f"rgba{tuple(int(color.lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) + (0.1,)}" )) fig.update_layout( template="plotly_dark", paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)', margin=dict(l=0, r=0, t=0, b=0), xaxis=dict(visible=False, fixedrange=True), yaxis=dict(visible=False, fixedrange=True), showlegend=False, height=80, ) return fig def generate_dashboard(): """Main function called to refresh the dashboard UI""" data = fetch_crypto_data() outputs = [] if not data: # If API fails, return empty placeholders return [gr.update(), gr.update()] * 4 for coin in data: # 1. Create HTML Block for Metrics color_24 = "#4caf50" if coin['chg_24'] >= 0 else "#ff5252" arrow = "▲" if coin['chg_24'] >= 0 else "▼" html_content = f"""