Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import plotly.express as px | |
| from cryptoindex import * | |
| import pandas as pd | |
| from updater import * | |
| from time import sleep | |
| from functools import partial | |
| import argparse | |
| import os | |
| from supabase import Client | |
| from supabase.client import ClientOptions | |
| import httpx | |
| from datetime import datetime | |
| import hashlib | |
| import json | |
| import uuid | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| supabase_url = os.getenv("SUPABASE_URL", "") | |
| supabase_key = os.getenv("SUPABASE_KEY", "") | |
| print(f"Supabase URL: {supabase_url[:30]}..." if supabase_url else "No Supabase URL") | |
| print(f"Supabase Key: {supabase_key[:20]}..." if supabase_key else "No Supabase Key") | |
| try: | |
| if supabase_url and supabase_key: | |
| # Create client manually to avoid proxy issues in HF Spaces | |
| options = ClientOptions( | |
| headers={ | |
| "apikey": supabase_key, | |
| "Authorization": f"Bearer {supabase_key}" | |
| }, | |
| schema="public", | |
| auto_refresh_token=True, | |
| persist_session=True, | |
| storage_options={}, | |
| realtime_options={} | |
| ) | |
| # Create HTTP client without proxy | |
| http_client = httpx.Client() | |
| # Initialize Supabase client | |
| supabase = Client(supabase_url, supabase_key, options) | |
| # Test the connection | |
| test_response = supabase.table('index_cache').select('id').limit(1).execute() | |
| print("Supabase connection test successful") | |
| else: | |
| print("Missing Supabase credentials") | |
| supabase = None | |
| except Exception as e: | |
| print(f"Supabase initialization error: {e}") | |
| print(f"Error details: {type(e).__name__}") | |
| import traceback | |
| traceback.print_exc() | |
| supabase = None | |
| # Don't update weights at startup - it might fail without proper env vars | |
| # update_weights1() is called later when needed | |
| def get_cache_key(start_date: str, end_date: str, locale: str, market_type: str) -> str: | |
| """Generate a unique cache key for the given parameters.""" | |
| key_string = f"{start_date}_{end_date}_{locale}_{market_type}" | |
| return hashlib.md5(key_string.encode()).hexdigest() | |
| def get_or_create_session(request: gr.Request) -> str: | |
| """Get or create a session ID from the Gradio request.""" | |
| if hasattr(request, 'session_hash'): | |
| return request.session_hash | |
| return str(uuid.uuid4()) | |
| def fetch_from_cache(cache_key: str): | |
| """Fetch index data from Supabase cache.""" | |
| if not supabase: | |
| print("Supabase client not initialized") | |
| return None | |
| try: | |
| print(f"Fetching cache for key: {cache_key}") | |
| response = supabase.table('index_cache').select('*').eq('cache_key', cache_key).execute() | |
| if response.data and len(response.data) > 0: | |
| data = response.data[0] | |
| v_data = pd.read_json(data['index_data']) | |
| v_data.index = pd.to_datetime(v_data.index) | |
| print(f"Cache hit for key: {cache_key}") | |
| return v_data | |
| else: | |
| print(f"Cache miss for key: {cache_key}") | |
| except Exception as e: | |
| print(f"Cache fetch error: {e}") | |
| print(f"Error type: {type(e)}") | |
| if hasattr(e, 'response'): | |
| print(f"Response: {e.response}") | |
| return None | |
| def save_to_cache(cache_key: str, v_data: pd.DataFrame, start_date: str, end_date: str, | |
| locale: str, market_type: str): | |
| """Save index data to Supabase cache.""" | |
| if not supabase: | |
| return | |
| try: | |
| cache_data = { | |
| 'cache_key': cache_key, | |
| 'start_date': start_date, | |
| 'end_date': end_date, | |
| 'locale': locale, | |
| 'market_type': market_type, | |
| 'index_data': v_data.to_json(), | |
| 'created_at': datetime.now().isoformat() | |
| } | |
| supabase.table('index_cache').upsert(cache_data).execute() | |
| except Exception as e: | |
| print(f"Cache save error: {e}") | |
| def get_user_weights(session_id: str, locale: str, market_type: str): | |
| """Get user-specific weights from Supabase.""" | |
| if not supabase: | |
| return None | |
| try: | |
| response = supabase.table('user_weights').select('*').eq('session_id', session_id).eq('locale', locale).eq('market_type', market_type).order('created_at', desc=True).limit(1).execute() | |
| if response.data and len(response.data) > 0: | |
| weights_data = response.data[0]['weights_data'] | |
| return pd.read_json(weights_data) | |
| except Exception as e: | |
| print(f"Error fetching user weights: {e}") | |
| return None | |
| def save_user_weights(session_id: str, weights_df: pd.DataFrame, locale: str, market_type: str): | |
| """Save user-specific weights to Supabase.""" | |
| if not supabase: | |
| return | |
| try: | |
| weights_data = { | |
| 'session_id': session_id, | |
| 'locale': locale, | |
| 'market_type': market_type, | |
| 'weights_data': weights_df.to_json(), | |
| 'created_at': datetime.now().isoformat() | |
| } | |
| supabase.table('user_weights').insert(weights_data).execute() | |
| except Exception as e: | |
| print(f"Error saving user weights: {e}") | |
| def plot_index_prices(start_date, end_date, request: gr.Request, **kwargs): | |
| """Plot historical index prices with caching.""" | |
| session_id = get_or_create_session(request) | |
| locale = kwargs.get('locale', 'global') | |
| market_type = kwargs.get('market_type', 'crypto') | |
| cache_key = get_cache_key(start_date, end_date, locale, market_type) | |
| v = fetch_from_cache(cache_key) | |
| if v is None: | |
| cryptodf = fetch_crypto_data(start_date=start_date, end_date=end_date, **kwargs) | |
| v, _ = get_crypto_index(cryptodf, func=np.sqrt) | |
| save_to_cache(cache_key, v, start_date, end_date, locale, market_type) | |
| _, _, _, output = do_sharpe(v.close) | |
| fig = px.line(v, x=v.index, y='close', title='Index Prices') | |
| fig.update_xaxes(rangeslider_visible=True) | |
| return fig, output | |
| def realtime_update_weighted_prices(request: gr.Request, locale='global', market_type='crypto'): | |
| """Update real-time prices with user-specific weights.""" | |
| session_id = get_or_create_session(request) | |
| if should_update_weights(): | |
| weights_df = update_weights(locale=locale, market_type=market_type) | |
| save_user_weights(session_id, weights_df, locale, market_type) | |
| last_day = get_user_weights(session_id, locale, market_type) | |
| if last_day is None: | |
| weights_df = update_weights(locale=locale, market_type=market_type) | |
| save_user_weights(session_id, weights_df, locale, market_type) | |
| last_day = weights_df | |
| prices = update_day(last_day) | |
| _, _, _, output = do_sharpe(prices, days=False) | |
| fig = px.line(prices, x=prices.index, y=prices.values, title='Index Today') | |
| return fig, output | |
| def make_graph(choice, start_date=None, end_date=None, request: gr.Request = None, **kwargs): | |
| """Create graph based on user choice.""" | |
| if choice == "Historical": | |
| fig, stats = plot_index_prices(start_date, end_date, request, **kwargs) | |
| else: | |
| fig, stats = realtime_update_weighted_prices(request, **kwargs) | |
| return gr.Plot(fig), gr.Markdown(stats) | |
| def initialize_database(): | |
| """Initialize Supabase tables if they don't exist.""" | |
| if not supabase: | |
| print("Supabase not configured. Running in local mode.") | |
| return | |
| print("Supabase connected successfully!") | |
| if __name__ == "__main__": | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--locale", default='global', help="the locale") | |
| parser.add_argument("--market_type", default='crypto', help="the market type") | |
| parser.add_argument("--share", action="store_true", help="share the interface") | |
| args = parser.parse_args() | |
| initialize_database() | |
| # Don't call update_weights at startup - let it happen on first use | |
| # update_weights1(locale=args.locale, market_type=args.market_type) | |
| with gr.Blocks() as iface: | |
| gr.Markdown("# Crypto Index Tracker (Supabase Edition)") | |
| gr.Markdown("Each user session has isolated data and computations are cached.") | |
| startdatebox = gr.Textbox(label="Start Date", placeholder="YYYY-MM-DD") | |
| enddatebox = gr.Textbox(label="End Date", placeholder="YYYY-MM-DD") | |
| radio = gr.Radio(choices=["Historical", "Real-time"], label="Graph Type", value="Historical") | |
| update_button = gr.Button("Update Graph") | |
| theplot = gr.Plot() | |
| thestats = gr.Markdown() | |
| make_graph_partial = partial(make_graph, locale=args.locale, market_type=args.market_type) | |
| radio.change( | |
| fn=make_graph_partial, | |
| inputs=[radio, startdatebox, enddatebox], | |
| outputs=[theplot, thestats] | |
| ) | |
| update_button.click( | |
| fn=make_graph_partial, | |
| inputs=[radio, startdatebox, enddatebox], | |
| outputs=[theplot, thestats] | |
| ) | |
| # Detect if running on Hugging Face Spaces | |
| if os.getenv("SPACE_ID"): | |
| iface.launch() | |
| else: | |
| iface.launch(server_port=7860, server_name="0.0.0.0", share=args.share) |