import gradio as gr import numpy as np import matplotlib.pyplot as plt import math from scipy.special import comb # --- Funções Matemáticas (O Coração do Teorema - sem alterações) --- def bernstein_poly(i, n, t): """ O polinômio de Bernstein, base para as curvas de Bézier. """ return comb(n, i) * (t**(i)) * ((1 - t)**(n - i)) def bezier_curve(points, n_times=1000): """ Gera uma curva de Bézier a partir de uma lista de pontos de controle. """ n_points = len(points) x_points = np.array([p[0] for p in points]) y_points = np.array([p[1] for p in points]) t = np.linspace(0.0, 1.0, n_times) polynomial_array = np.array([bernstein_poly(i, n_points - 1, t) for i in range(0, n_points)]) x_vals = np.dot(x_points, polynomial_array) y_vals = np.dot(y_points, polynomial_array) return x_vals, y_vals def aprender_com_o_eco(pontos_do_eco: list) -> dict: """ Calcula a essência do movimento (direção e vetor) do eco. """ if len(pontos_do_eco) < 2: return {"bearing_rad": 0, "velocity_vector": np.array([0, 0])} p1, p2 = np.array(pontos_do_eco[0]), np.array(pontos_do_eco[-1]) vetor_velocidade = p2 - p1 bearing_radianos = math.atan2(vetor_velocidade[1], vetor_velocidade[0]) return {"bearing_rad": bearing_radianos, "velocity_vector": vetor_velocidade} # --- Função Principal do Gradio (A Interface do Laboratório Completo) --- def gerar_grafico_dinamico(inflexao1_x, inflexao1_y, inflexao2_x, inflexao2_y, destino_x, destino_y, eco_vetores): """ Gera e plota a jornada com os caminhos da Criança A e B sendo totalmente dinâmicos. """ # 1. DEFINIÇÃO DOS PONTOS DA JORNADA, AGORA QUASE TODOS DINÂMICOS p1_inicio = np.array([0, 0]) # Pontos de inflexão da Criança A (vindo da UI) p2_inflexao1 = np.array([inflexao1_x, inflexao1_y]) p3_inflexao2 = np.array([inflexao2_x, inflexao2_y]) # Ponto de encontro é o ponto final da Criança A e o inicial da B. # Vamos fixá-lo para manter um ponto de referência estável. p4_encontro = np.array([75, 45]) # Destino da Criança B (vindo da UI) p5_destino = np.array([destino_x, destino_y]) # 2. GERAR A CURVA DINÂMICA DA CRIANÇA A pontos_curva_a = [p1_inicio, p2_inflexao1, p3_inflexao2, p4_encontro] x_a, y_a = bezier_curve(pontos_curva_a, n_times=1000) # 3. ISOLAR O ECO NUMERO_DE_VETORES_ECO = int(eco_vetores) if NUMERO_DE_VETORES_ECO < 2: NUMERO_DE_VETORES_ECO = 2 x_eco = x_a[-NUMERO_DE_VETORES_ECO:] y_eco = y_a[-NUMERO_DE_VETORES_ECO:] pontos_do_eco = list(zip(x_eco, y_eco)) # 4. CRIANÇA B APRENDE COM O ECO essencia_movimento = aprender_com_o_eco(pontos_do_eco) vetor_aprendido = essencia_movimento["velocity_vector"] # 5. GERAR A CURVA DINÂMICA DA CRIANÇA B ponto_controle_b = p4_encontro + vetor_aprendido pontos_curva_b = [p4_encontro, ponto_controle_b, p5_destino] x_b, y_b = bezier_curve(pontos_curva_b, n_times=1000) # 6. PLOTAGEM COMPLETA fig, ax = plt.subplots(figsize=(12, 9)) fig.patch.set_facecolor('black') ax.set_facecolor('black') ax.spines['bottom'].set_color('white') ax.spines['left'].set_color('white') ax.spines['top'].set_color('black') ax.spines['right'].set_color('black') ax.tick_params(axis='x', colors='white') ax.tick_params(axis='y', colors='white') ax.plot(x_a, y_a, label='Caminho da Criança A (Seu Input)', color='cyan', linewidth=2) ax.plot(x_b, y_b, label='Continuidade da Criança B (Gerado)', color='lime', linewidth=2, linestyle='--') ax.plot(x_eco, y_eco, label=f'Eco de Memória ({NUMERO_DE_VETORES_ECO} vetores)', color='magenta', linewidth=4) pontos_controle_completos = np.array([p1_inicio, p2_inflexao1, p3_inflexao2, p4_encontro, ponto_controle_b, p5_destino]) ax.plot(pontos_controle_completos[:, 0], pontos_controle_completos[:, 1], 'o--', color='lightcoral', markersize=8, alpha=0.6, label='Estrutura de Controle') ax.plot(p4_encontro[0], p4_encontro[1], 'o', color='yellow', markersize=12, markeredgecolor='black', label='Ponto de Encontro (Fixo)') ax.plot(p5_destino[0], p5_destino[1], 'X', color='red', markersize=12, markeredgecolor='white', label='Destino da Criança B') ax.set_title('Laboratório de Continuidade Causal', color='white', fontsize=16) ax.set_xlabel('Eixo X', color='white', fontsize=12) ax.set_ylabel('Eixo Y', color='white', fontsize=12) legend = ax.legend(facecolor='#111111', edgecolor='white', framealpha=0.5) for text in legend.get_texts(): text.set_color('white') ax.grid(True, linestyle='--', color='gray', alpha=0.3) ax.set_aspect('equal', adjustable='box') caminho_figura = "laboratorio_completo.png" plt.savefig(caminho_figura, bbox_inches='tight', pad_inches=0.1, dpi=100, transparent=True) plt.close(fig) info_vetor = f"Vetor de Inércia Aprendido: ({vetor_aprendido[0]:.2f}, {vetor_aprendido[1]:.2f}) | Direção: {math.degrees(essencia_movimento['bearing_rad']):.2f}°" return caminho_figura, info_vetor # --- Interface Gradio --- with gr.Blocks(theme=gr.themes.Base(primary_hue="teal")) as demo: gr.Markdown( """ # 🔬 Laboratório de Continuidade Causal (Versão Completa) Molde a trajetória completa! Use os controles para definir tanto o **caminho da Criança A** (o passado) quanto o **destino da Criança B** (o futuro). Observe como a inércia é calculada e aplicada para qualquer estilo de movimento. """ ) with gr.Row(): with gr.Column(scale=1): gr.Markdown("### 🎮 Controles da Simulação") with gr.Accordion("Definir Caminho da Criança A (O Passado)", open=True): gr.Markdown("Começa em `[0,0]` e termina no ponto fixo de encontro `[75,45]`.") inflexao1_x = gr.Slider(-50, 150, value=25, label="Vetor 2 (Inflexão 1) - X", visible=False) inflexao1_y = gr.Slider(-50, 150, value=15, label="Vetor 2 (Inflexão 1) - Y") inflexao2_x = gr.Slider(-50, 150, value=50, label="Vetor 3 (Inflexão 2) - X", visible=False) inflexao2_y = gr.Slider(-50, 150, value=30, label="Vetor 3 (Inflexão 2) - Y") with gr.Accordion("Definir Caminho da Criança B (O Futuro)", open=True): destino_x_input = gr.Slider(-50, 150, value=100, label="Destino Final (X)", visible=False) destino_y_input = gr.Slider(-50, 150, value=90, label="Destino Final (Y)") with gr.Accordion("Configurações do Aprendizado", open=False): eco_input = gr.Slider(2, 300, value=150, step=1, label="Nº de Vetores no Eco de Memória") with gr.Column(scale=2): gr.Markdown("### 📊 Visualização da Jornada") info_output = gr.Textbox(label="Dados do Aprendizado (Calculado)", interactive=False) plot_output = gr.Image(label="Gráfico da Continuidade", type="filepath") # Lista completa de componentes de entrada inputs = [inflexao1_x, inflexao1_y, inflexao2_x, inflexao2_y, destino_x_input, destino_y_input, eco_input] # Conecta todos os sliders à função para atualização em tempo real for component in inputs: component.change(fn=gerar_grafico_dinamico, inputs=inputs, outputs=[plot_output, info_output]) # Carga inicial do aplicativo demo.load(fn=gerar_grafico_dinamico, inputs=inputs, outputs=[plot_output, info_output]) if __name__ == "__main__": demo.launch()