import gradio as gr import uuid import subprocess import time import asyncio import re USER_ID = str(uuid.uuid4()) # Iniciar o servidor MCP em background # subprocess.Popen(["python", "mcp_players_table_sql.py"]) # subprocess.Popen(["python", "mcp_team_table_sql.py"]) # subprocess.Popen(["python", "mcp_one_player_supabase.py"]) # time.sleep(3) # subprocess.Popen(["python", "mcp_graph_server.py"]) # time.sleep(3) import pandas as pd # Caminho do CSV já presente no repositório do Space (coloque seu arquivo em /, ou numa pasta). CSV_PATH = "barca.csv" # ajuste para o seu caminho real # Carregamento único no startup try: _df_full = pd.read_csv(CSV_PATH) _df_preview = _df_full.head(100) _df_meta = f"Source: Author • Rows: {len(_df_full)} • Columns: {len(_df_full.columns)}" except Exception as e: _df_full = None _df_preview = None _df_meta = f"Erro ao carregar CSV em startup: {e}" #from place_holder_image import PLACEHOLDER_IMAGE, get_current_chart from main_agent import stream_agent_response_safe, agent_conventional_response from utils import CUSTOM_CSS async def simulate_streaming_adaptive(full_text: str): """Streaming adaptativo com delays diferentes para pontuação""" words = re.findall(r'\S+\s*', full_text) current_text = "" for word in words: current_text += word if word.strip().endswith(('.', '!', '?')): delay = 0.15 elif word.strip().endswith((',', ';', ':')): delay = 0.08 else: delay = 0.04 await asyncio.sleep(delay) yield current_text async def respond(message, history): """Função de resposta com streaming + atualização de gráfico""" message = str(message) print(f"Message received: {message}") try: print("Obtendo resposta completa do agente...") full_response = await stream_agent_response_safe(message) print(f"Resposta obtida: {len(full_response)} caracteres") # Simular streaming da resposta async for text_chunk in simulate_streaming_adaptive(full_response): yield text_chunk except Exception as e: print(f"Erro durante o processamento: {e}") import traceback traceback.print_exc() yield f"❌ Erro: {str(e)}", get_current_chart() # def refresh_chart(): # """Atualiza a visualização do gráfico""" # return get_current_chart() if __name__ == "__main__": with gr.Blocks( title="Barcelona Analytics Platform", theme=gr.themes.Soft( primary_hue="blue", secondary_hue="slate", neutral_hue="slate", font=[gr.themes.GoogleFont("Inter"), "sans-serif"], font_mono=[gr.themes.GoogleFont("JetBrains Mono"), "monospace"] ), css=CUSTOM_CSS ) as demo: gr.Markdown( """ ## Data Analyst Agent with FC Barcelona Statistics (2020/2021) """ ) with gr.Tabs() as tabs: # ABA 1: ANALYSIS & CHAT with gr.Tab("Chat", id=0, scale=0): #gr.Markdown("### Intelligent Assistant") chatbot = gr.Chatbot( type="messages", label="", height=400, show_copy_button=True, scale=0 ) with gr.Row(): msg = gr.Textbox( placeholder="Ask about players, matches, or request visualizations...", label="Your Query", lines=2, scale=4, show_label=False ) submit_btn = gr.Button("Send", variant="primary", scale=1, size="lg") with gr.Accordion("📋 Query Examples", open=False): gr.Examples( examples=[ "Return the top 10 players by total xG and assists combined", "Create a bar chart showing the top 5 players with most passes", "Find players with at least 900 minutes who rank in the top 5% for progressive passes and top 10% for xG assisted in 2020/2021, returning player, minutes, prog_passes, xA, and z-scores" ], inputs=msg, label="" ) # ABA 2: DATA VISUALIZATION # with gr.Tab("Generated Chart", id=1): # gr.Markdown( # """ # ### Interactive Visualizations # Charts and graphs generated by the AI assistant will appear here. # Request visualizations in the Analysis tab to see them rendered. # """ # ) # chart_display = gr.Image( # value=PLACEHOLDER_IMAGE, # label="", # type="pil", # height=360, # show_label=False, # show_download_button=True, # show_share_button=False # ) # with gr.Row(): # refresh_btn = gr.Button("🔄 Refresh Visualization", variant="secondary", size="lg") # gr.Markdown("_Last updated: Live_", elem_classes="status-badge") with gr.Tab("CSV Source Data", id=2): gr.Markdown("### Data consulted by the Agent\nStatic view (100 lines) from preloaded dataset.", elem_classes=["section-title"]) meta = gr.Markdown(value=_df_meta) df_view = gr.Dataframe( value=_df_preview, label="Preview - 100 lines", wrap=False, interactive=False ) # Footer informativo gr.Markdown( """ --- **Data Source:** SQL Database • **AI Model:** Groq-powered Analysis • **Coverage:** 1 Seasons (2020-2021) """ ) async def respond_and_update(message, history): """Responde e retorna tanto o chat quanto o gráfico atualizado""" if not message.strip(): yield history return # Adicionar mensagem do usuário history.append(gr.ChatMessage(role="user", content=message)) try: # Obter resposta # full_response = await asyncio.wait_for( # stream_agent_response_safe(message), # timeout=120.0 # ) full_response = await agent_conventional_response(message) # Adicionar mensagem inicial do assistente history.append(gr.ChatMessage(role="assistant", content="")) # Streaming adaptativo async for text_chunk in simulate_streaming_adaptive(full_response): history[-1] = gr.ChatMessage(role="assistant", content=text_chunk) yield history except asyncio.TimeoutError: history.append([message, "⏱️ Timeout: consulta demorou muito"]) yield history, get_current_chart() except Exception as e: print(f"Erro: {e}") import traceback traceback.print_exc() history.append(gr.ChatMessage(role="assistant", content=f"⚠️ Error: {str(e)}")) yield history # Eventos submit_btn.click( fn=respond_and_update, inputs=[msg, chatbot], outputs=[chatbot] ).then( lambda: "", None, [msg] ) msg.submit( fn=respond_and_update, inputs=[msg, chatbot], outputs=[chatbot] ).then( lambda: "", None, [msg] ) # refresh_btn.click( # fn=refresh_chart, # inputs=[], # outputs=[chart_display] # ) demo.launch(ssr_mode=False, share=False)