x2XcarleX2x commited on
Commit
197e07d
·
verified ·
1 Parent(s): 4573118

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -122
app.py CHANGED
@@ -1,161 +1,144 @@
1
  import gradio as gr
2
  import numpy as np
3
- import plotly.graph_objects as go
 
 
4
  import math
5
  from scipy.special import comb
 
 
6
 
7
- # --- Funções Matemáticas (Adaptadas para 3D) ---
8
-
9
  def bernstein_poly(i, n, t):
10
- """ O polinômio de Bernstein (base para Bézier). """
11
  return comb(n, i) * (t**(i)) * ((1 - t)**(n - i))
12
 
13
  def bezier_curve_3d(points, n_times=100):
14
- """ Gera uma curva de Bézier 3D a partir de pontos de controle. """
15
  n_points = len(points)
16
- x_points = np.array([p[0] for p in points])
17
- y_points = np.array([p[1] for p in points])
18
- z_points = np.array([p[2] for p in points])
19
  t = np.linspace(0.0, 1.0, n_times)
20
  polynomial_array = np.array([bernstein_poly(i, n_points - 1, t) for i in range(n_points)])
21
- x_vals = np.dot(x_points, polynomial_array)
22
- y_vals = np.dot(y_points, polynomial_array)
23
- z_vals = np.dot(z_points, polynomial_array)
24
  return x_vals, y_vals, z_vals
25
 
26
- def aprender_com_o_eco_3d(pontos_do_eco: list) -> dict:
27
- """ Calcula a essência do movimento 3D (vetor) do eco. """
28
- if len(pontos_do_eco) < 2:
29
- return {"velocity_vector": np.array([0, 0, 0])}
30
  p1, p2 = np.array(pontos_do_eco[0]), np.array(pontos_do_eco[-1])
31
- vetor_velocidade = p2 - p1
32
- return {"velocity_vector": vetor_velocidade}
33
 
34
- # --- Função Principal do Gradio (O Laboratório 3D Interativo) ---
35
 
36
- def gerar_grafico_3d_dinamico(
37
- inflexao1_x, inflexao1_y, inflexao1_z,
38
- inflexao2_x, inflexao2_y, inflexao2_z,
39
- eco_vetores
40
- ):
41
  """
42
- Gera e plota a jornada 3D completa com base nos inputs da UI.
43
  """
44
- # 1. DEFINIÇÃO DOS PONTOS DA JORNADA
45
- p1_inicio = np.array([0, 0, 0])
46
- p2_inflexao1 = np.array([inflexao1_x, inflexao1_y, inflexao1_z])
47
- p3_inflexao2 = np.array([inflexao2_x, inflexao2_y, inflexao2_z])
48
- p4_encontro = np.array([75, 45, 10])
49
-
50
- # Para o loop, o destino final deve ser o ponto de início.
51
- p5_destino = p1_inicio
52
-
53
- # 2. GERAR A CURVA DA CRIANÇA A
54
- pontos_curva_a = [p1_inicio, p2_inflexao1, p3_inflexao2, p4_encontro]
55
- x_a, y_a, z_a = bezier_curve_3d(pontos_curva_a)
56
- caminho_a = list(zip(x_a, y_a, z_a))
57
-
58
- # 3. APRENDER COM O ECO
59
- num_eco = int(eco_vetores)
60
- if num_eco < 2: num_eco = 2
61
- pontos_do_eco = caminho_a[-num_eco:]
62
- vetor_aprendido = aprender_com_o_eco_3d(pontos_do_eco)["velocity_vector"]
63
-
64
- # 4. GERAR A CURVA DA CRIANÇA B
65
- ponto_controle_b = p4_encontro + vetor_aprendido
66
- ponto_inflexao_retorno = p1_inicio - vetor_aprendido * 0.5
67
- pontos_curva_b = [p4_encontro, ponto_controle_b, ponto_inflexao_retorno, p5_destino]
68
- x_b, y_b, z_b = bezier_curve_3d(pontos_curva_b)
69
-
70
- # 5. PREPARAR DADOS PARA O PLOTLY
71
-
72
- # Caminho A
73
- trace_a = go.Scatter3d(x=x_a, y=y_a, z=z_a, mode='lines', line=dict(color='cyan', width=5), name='Caminho A (Passado)')
74
-
75
- # Caminho B
76
- trace_b = go.Scatter3d(x=x_b, y=y_b, z=z_b, mode='lines', line=dict(color='lime', width=5, dash='dash'), name='Caminho B (Convergência)')
77
-
78
- # Eco de Memória
79
- x_eco, y_eco, z_eco = zip(*pontos_do_eco)
80
- trace_eco = go.Scatter3d(x=x_eco, y=y_eco, z=z_eco, mode='lines', line=dict(color='magenta', width=10), name=f'Eco de Memória ({num_eco} vetores)')
81
 
82
- # Pontos de Controle e Waypoints
83
- pontos_controle = np.array([p1_inicio, p2_inflexao1, p3_inflexao2, p4_encontro, ponto_controle_b, ponto_inflexao_retorno, p5_destino])
84
- trace_controle = go.Scatter3d(x=pontos_controle[:,0], y=pontos_controle[:,1], z=pontos_controle[:,2], mode='markers', marker=dict(color='lightcoral', size=5), name='Estrutura de Controle')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
 
86
- waypoints = np.array([p1_inicio, p4_encontro])
87
- trace_waypoints = go.Scatter3d(x=waypoints[:,0], y=waypoints[:,1], z=waypoints[:,2], mode='markers', marker=dict(color=['cyan', 'yellow'], size=12, symbol=['circle', 'diamond']), name='Waypoints (Início/Encontro)')
88
-
89
- # 6. CRIAR A FIGURA PLOTLY
90
- layout = go.Layout(
91
- title=dict(text='Laboratório de Continuidade Causal 3D', font=dict(color='white')),
92
- scene=dict(
93
- xaxis_title='Eixo X',
94
- yaxis_title='Eixo Y',
95
- zaxis_title='Eixo Z',
96
- xaxis=dict(gridcolor='gray', zerolinecolor='gray', color='white'),
97
- yaxis=dict(gridcolor='gray', zerolinecolor='gray', color='white'),
98
- zaxis=dict(gridcolor='gray', zerolinecolor='gray', color='white'),
99
- bgcolor='#111111'
100
- ),
101
- paper_bgcolor='#111111',
102
- legend=dict(font=dict(color='white'))
103
- )
104
-
105
- fig = go.Figure(data=[trace_a, trace_b, trace_eco, trace_controle, trace_waypoints], layout=layout)
106
-
107
- info_vetor = f"Vetor de Inércia Aprendido: ({vetor_aprendido[0]:.2f}, {vetor_aprendido[1]:.2f}, {vetor_aprendido[2]:.2f})"
 
 
 
 
108
 
109
- return fig, info_vetor
110
 
111
  # --- Interface Gradio ---
112
 
113
- with gr.Blocks(theme=gr.themes.Base(primary_hue="green", secondary_hue="blue")) as demo:
114
  gr.Markdown(
115
  """
116
- # 🔬 Laboratório de Continuidade Causal 3D Interativo
117
- Molde a trajetória no espaço! Use os sliders para definir os pontos de inflexão da "Criança A".
118
- O sistema irá aprender a inércia (vetor de movimento) a partir do "Eco de Memória" (em magenta) e projetar a trajetória contínua da "Criança B" de volta ao início, formando um loop.
119
- **Use o mouse para girar e dar zoom no gráfico 3D.**
120
  """
121
  )
122
 
123
  with gr.Row():
124
  with gr.Column(scale=1):
125
- gr.Markdown("### 🎮 Controles da Simulação")
 
 
126
 
127
- with gr.Accordion("Definir Ponto de Inflexão 1", open=True):
128
- inflexao1_x = gr.Slider(-50, 150, value=25, label="Posição X")
129
- inflexao1_y = gr.Slider(-50, 150, value=60, label="Posição Y")
130
- inflexao1_z = gr.Slider(-50, 150, value=50, label="Posição Z (Altura)")
131
-
132
- with gr.Accordion("Definir Ponto de Inflexão 2", open=True):
133
- inflexao2_x = gr.Slider(-50, 150, value=60, label="Posição X")
134
- inflexao2_y = gr.Slider(-50, 150, value=20, label="Posição Y")
135
- inflexao2_z = gr.Slider(-50, 150, value=-30, label="Posição Z (Altura)")
136
 
137
- with gr.Accordion("Configurações do Aprendizado", open=True):
138
- eco_input = gr.Slider(2, 100, value=50, step=1, label="Tamanho do Eco de Memória ( de Vetores)")
 
 
139
 
140
- info_output = gr.Textbox(label="Dados do Aprendizado (Calculado)", interactive=False)
141
-
142
- with gr.Column(scale=3):
143
- gr.Markdown("### 📊 Visualização da Jornada 3D")
144
- # Usamos gr.Plot para renderizar a figura do Plotly
145
- plot_output = gr.Plot()
146
-
147
- inputs = [
148
- inflexao1_x, inflexao1_y, inflexao1_z,
149
- inflexao2_x, inflexao2_y, inflexao2_z,
150
- eco_input
151
- ]
152
-
153
- # Conecta todos os sliders à função para atualização em tempo real
154
- for component in inputs:
155
- component.change(fn=gerar_grafico_3d_dinamico, inputs=inputs, outputs=[plot_output, info_output])
156
 
157
- # Carga inicial do aplicativo
158
- demo.load(fn=gerar_grafico_3d_dinamico, inputs=inputs, outputs=[plot_output, info_output])
 
 
 
159
 
160
  if __name__ == "__main__":
161
  demo.launch()
 
1
  import gradio as gr
2
  import numpy as np
3
+ import matplotlib.pyplot as plt
4
+ from mpl_toolkits.mplot3d import Axes3D
5
+ from matplotlib.animation import FuncAnimation
6
  import math
7
  from scipy.special import comb
8
+ import random
9
+ import json
10
 
11
+ # --- Funções Matemáticas (as mesmas que já dominamos) ---
 
12
  def bernstein_poly(i, n, t):
 
13
  return comb(n, i) * (t**(i)) * ((1 - t)**(n - i))
14
 
15
  def bezier_curve_3d(points, n_times=100):
 
16
  n_points = len(points)
17
+ x_points, y_points, z_points = np.array([p[0] for p in points]), np.array([p[1] for p in points]), np.array([p[2] for p in points])
 
 
18
  t = np.linspace(0.0, 1.0, n_times)
19
  polynomial_array = np.array([bernstein_poly(i, n_points - 1, t) for i in range(n_points)])
20
+ x_vals, y_vals, z_vals = np.dot(x_points, polynomial_array), np.dot(y_points, polynomial_array), np.dot(z_points, polynomial_array)
 
 
21
  return x_vals, y_vals, z_vals
22
 
23
+ def aprender_com_o_eco_3d(pontos_do_eco: list):
24
+ if len(pontos_do_eco) < 2: return {"velocity_vector": np.array([0, 0, 0])}
 
 
25
  p1, p2 = np.array(pontos_do_eco[0]), np.array(pontos_do_eco[-1])
26
+ return {"velocity_vector": p2 - p1}
 
27
 
28
+ # --- Função Principal do Gradio (O Gerador de Ciclos) ---
29
 
30
+ def gerar_proximo_ciclo(estado_anterior_json: str, progress=gr.Progress(track_tqdm=True)):
 
 
 
 
31
  """
32
+ Gera um único trecho da jornada (de A para B) e o renderiza como um vídeo.
33
  """
34
+ progress(0, desc="Decodificando estado anterior...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ # 1. Carrega o estado do ciclo anterior (ou cria um novo se for o primeiro)
37
+ if estado_anterior_json:
38
+ estado = json.loads(estado_anterior_json)
39
+ ponto_a = np.array(estado["ponto_b"]) # O destino se torna a origem
40
+ vetor_inercia_anterior = np.array(estado["vetor_inercia"])
41
+ else: # Primeiro ciclo
42
+ ponto_a = np.array([0., 0., 0.])
43
+ vetor_inercia_anterior = np.array([10., 10., 10.])
44
+
45
+ progress(0.1, desc="Gerando novo checkpoint aleatório...")
46
+ # 2. Gera um novo destino (Ponto B)
47
+ ponto_b = np.random.rand(3) * 120 - 60
48
+
49
+ progress(0.2, desc="Calculando trajetória com convergência...")
50
+ # 3. Calcula a nova trajetória
51
+ ponto_controle = ponto_a + vetor_inercia_anterior
52
+ pontos_curva = [ponto_a, ponto_controle, ponto_b]
53
+ x_traj, y_traj, z_traj = bezier_curve_3d(pontos_curva, n_times=120) # 120 frames
54
+ total_frames = len(x_traj)
55
+
56
+ # 4. Aprende o "eco" para o próximo ciclo
57
+ tamanho_eco = 30
58
+ pontos_eco = list(zip(x_traj[-tamanho_eco:], y_traj[-tamanho_eco:], z_traj[-tamanho_eco:]))
59
+ vetor_inercia_novo = aprender_com_o_eco_3d(pontos_eco)["velocity_vector"]
60
+
61
+ # 5. Salva o novo estado para o próximo clique do botão
62
+ estado_novo = {
63
+ "ponto_a": ponto_a.tolist(),
64
+ "ponto_b": ponto_b.tolist(),
65
+ "vetor_inercia": vetor_inercia_novo.tolist()
66
+ }
67
+ estado_novo_json = json.dumps(estado_novo)
68
+
69
+ # 6. Setup da Animação
70
+ fig = plt.figure(figsize=(8, 8)); ax = fig.add_subplot(111, projection='3d')
71
+ fig.patch.set_facecolor('#111111'); ax.set_facecolor('#111111')
72
 
73
+ bola, = ax.plot([], [], [], 'o', color='red', markersize=10, markeredgecolor='white')
74
+ ax.set_xlim(-70, 70); ax.set_ylim(-70, 70); ax.set_zlim(-70, 70)
75
+ ax.set_xticklabels([]); ax.set_yticklabels([]); ax.set_zticklabels([])
76
+
77
+ def update(frame):
78
+ # Desenha a cena estática em cada frame
79
+ ax.cla() # Limpa o eixo para redesenhar
80
+ ax.set_xlim(-70, 70); ax.set_ylim(-70, 70); ax.set_zlim(-70, 70)
81
+ ax.set_xticklabels([]); ax.set_yticklabels([]); ax.set_zticklabels([])
82
+ ax.plot(x_traj, y_traj, z_traj, color='cyan', linewidth=2, alpha=0.5)
83
+ ax.scatter(*ponto_a, s=400, c='lime', alpha=0.7, label='Ponto A (Início)')
84
+ ax.scatter(*ponto_b, s=400, c='yellow', marker='X', alpha=0.7, label='Ponto B (Destino)')
85
+
86
+ # Anima a bola
87
+ bola.set_data_3d([x_traj[frame]], [y_traj[frame]], [z_traj[frame]])
88
+ ax.view_init(elev=30., azim=frame * 0.7)
89
+ return bola,
90
+
91
+ # 7. Renderiza e Salva o Vídeo
92
+ progress(0.5, desc="Renderizando animação do ciclo...")
93
+ ani = FuncAnimation(fig, update, frames=total_frames, interval=33, blit=False)
94
+ output_filename = "ciclo_atual.mp4"
95
+ ani.save(output_filename, writer='ffmpeg', fps=30, dpi=100, progress_callback=lambda i, n: progress(0.5 + 0.5 * (i/n), desc=f"Renderizando frame {i+1}/{n}"))
96
+ plt.close(fig)
97
+
98
+ info_ciclo = f"Ciclo Concluído.\nInício (A): {np.round(ponto_a, 1)}\nDestino (B): {np.round(ponto_b, 1)}\nInércia Aprendida: {np.round(vetor_inercia_novo, 1)}"
99
 
100
+ return output_filename, estado_novo_json, info_ciclo
101
 
102
  # --- Interface Gradio ---
103
 
104
+ with gr.Blocks(theme=gr.themes.Base(primary_hue="lime")) as demo:
105
  gr.Markdown(
106
  """
107
+ # 🌀 Simulador de Convergência Causal 3D Interativo
108
+ Clique em "Gerar Próximo Ciclo" para ver o agente (bola vermelha) viajar do checkpoint A (verde) para um novo checkpoint B (amarelo) aleatório.
109
+ A trajetória é guiada pela inércia aprendida do ciclo anterior. Cada clique gera a continuação da jornada.
 
110
  """
111
  )
112
 
113
  with gr.Row():
114
  with gr.Column(scale=1):
115
+ gr.Markdown("### ��� Controles")
116
+ # O estado é armazenado em um Textbox invisível
117
+ estado_oculto = gr.Textbox(label="Estado da Simulação (JSON)", interactive=True, visible=False)
118
 
119
+ info_output = gr.Textbox(label="Dados do Ciclo Atual", lines=4, interactive=False)
 
 
 
 
 
 
 
 
120
 
121
+ # Botão para iniciar o primeiro ciclo (sem estado anterior)
122
+ start_btn = gr.Button("🚀 Iniciar Simulação (Primeiro Ciclo)", variant="primary")
123
+ # Botão para continuar a simulação (usa o estado anterior)
124
+ next_btn = gr.Button("➡️ Gerar Próximo Ciclo", variant="secondary")
125
 
126
+ with gr.Column(scale=2):
127
+ gr.Markdown("### 📽️ Visualização do Ciclo")
128
+ video_output = gr.Video(label="Animação do Ciclo Atual", autoplay=True)
129
+
130
+ # Conexões dos botões
131
+ start_btn.click(
132
+ fn=lambda: gerar_proximo_ciclo(None), # Passa None para indicar o primeiro ciclo
133
+ inputs=None,
134
+ outputs=[video_output, estado_oculto, info_output]
135
+ )
 
 
 
 
 
 
136
 
137
+ next_btn.click(
138
+ fn=gerar_proximo_ciclo,
139
+ inputs=[estado_oculto],
140
+ outputs=[video_output, estado_oculto, info_output]
141
+ )
142
 
143
  if __name__ == "__main__":
144
  demo.launch()