Antigravity Agent commited on
Commit
575d372
·
1 Parent(s): f6dedb3

feat(ui): add animated architecture flow and 'How It Works' tab

Browse files
Files changed (3) hide show
  1. app.py +31 -9
  2. flow_module.py +85 -0
  3. theme.css +33 -0
app.py CHANGED
@@ -15,6 +15,7 @@ from verification_service import calculate_symbolic_score
15
  from consensus_fusion import evaluate_consensus
16
  from report_module import generate_mvm2_report, export_to_pdf
17
  from image_enhancing import ImageEnhancer
 
18
 
19
  # Initialize Engines
20
  ocr_engine = MVM2OCREngine()
@@ -91,6 +92,9 @@ def process_mvm2_pipeline(image, auto_enhance):
91
  latex_text = ocr_results['latex_output']
92
  ocr_conf = ocr_results['weighted_confidence']
93
 
 
 
 
94
  # 3. Multi-Agent Reasoning
95
  agent_responses = run_agent_orchestrator(latex_text)
96
 
@@ -144,7 +148,9 @@ def process_mvm2_pipeline(image, auto_enhance):
144
  pdf_path = os.path.join(tempfile.gettempdir(), f'MVM2_Report_{reports["report_id"]}.pdf')
145
  export_to_pdf(json.loads(reports['json']), pdf_path)
146
 
147
- return preview_img, latex_text, gauges_html, conf_bar, md_report, pdf_path
 
 
148
 
149
  # Build Interface
150
  with gr.Blocks(css=css_content, title="MVM²: Senior UI AI Dashboard") as demo:
@@ -171,13 +177,29 @@ with gr.Blocks(css=css_content, title="MVM²: Senior UI AI Dashboard") as demo:
171
 
172
  # --- CENTER STAGE: Canvas ---
173
  with gr.Column(scale=2):
174
- gr.Markdown("### 🎨 MVM² Verification Canvas")
175
- with gr.Group(elem_classes="glass-card"):
176
- canvas_latex = gr.Textbox(label="Canonical LaTeX Transcription", lines=2, interactive=False, elem_classes="monospace")
177
- calib_bar_html = gr.HTML()
178
-
179
- gr.Markdown("### 🪜 Dynamic Reasoning Trace")
180
- trace_html = gr.HTML()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
 
182
  # --- RIGHT PANEL: Signal Intel ---
183
  with gr.Column(scale=1, variant="panel"):
@@ -201,7 +223,7 @@ with gr.Blocks(css=css_content, title="MVM²: Senior UI AI Dashboard") as demo:
201
  run_btn.click(
202
  fn=process_mvm2_pipeline,
203
  inputs=[input_img, enhance_toggle],
204
- outputs=[preview_output, canvas_latex, signal_gauges, calib_bar_html, trace_html, download_btn]
205
  )
206
 
207
  if __name__ == "__main__":
 
15
  from consensus_fusion import evaluate_consensus
16
  from report_module import generate_mvm2_report, export_to_pdf
17
  from image_enhancing import ImageEnhancer
18
+ from flow_module import generate_flow_html
19
 
20
  # Initialize Engines
21
  ocr_engine = MVM2OCREngine()
 
92
  latex_text = ocr_results['latex_output']
93
  ocr_conf = ocr_results['weighted_confidence']
94
 
95
+ # Update flow for current state (Visual sync)
96
+ flow_html = generate_flow_html("reasoning") # Transitioning to reasoning
97
+
98
  # 3. Multi-Agent Reasoning
99
  agent_responses = run_agent_orchestrator(latex_text)
100
 
 
148
  pdf_path = os.path.join(tempfile.gettempdir(), f'MVM2_Report_{reports["report_id"]}.pdf')
149
  export_to_pdf(json.loads(reports['json']), pdf_path)
150
 
151
+ final_flow = generate_flow_html("success")
152
+
153
+ return preview_img, latex_text, gauges_html, conf_bar, md_report, pdf_path, final_flow
154
 
155
  # Build Interface
156
  with gr.Blocks(css=css_content, title="MVM²: Senior UI AI Dashboard") as demo:
 
177
 
178
  # --- CENTER STAGE: Canvas ---
179
  with gr.Column(scale=2):
180
+ with gr.Tabs():
181
+ with gr.TabItem("Solver Visualization"):
182
+ gr.Markdown("### 🎨 MVM² Verification Canvas")
183
+ with gr.Group(elem_classes="glass-card"):
184
+ canvas_latex = gr.Textbox(label="Canonical LaTeX Transcription", lines=2, interactive=False, elem_classes="monospace")
185
+ calib_bar_html = gr.HTML()
186
+
187
+ gr.Markdown("### 🪜 Dynamic Reasoning Trace")
188
+ trace_html = gr.HTML()
189
+
190
+ with gr.TabItem("How It Works (Architecture Flow)"):
191
+ gr.Markdown("### 🚀 Real-Time Pipeline Visualization")
192
+ flow_view = gr.HTML(generate_flow_html("idle"))
193
+ gr.Markdown(
194
+ """
195
+ **Pipeline Phases:**
196
+ 1. **Enhance:** CLAHE & Gaussian Blur noise reduction.
197
+ 2. **OCR:** Pix2Text LaTeX structure reconstruction.
198
+ 3. **Reasoning:** Quad-agent parallel logic processing.
199
+ 4. **Verification:** SymPy deterministic symbolic check.
200
+ 5. **Consensus:** Multi-signal weighted confidence fusion.
201
+ """
202
+ )
203
 
204
  # --- RIGHT PANEL: Signal Intel ---
205
  with gr.Column(scale=1, variant="panel"):
 
223
  run_btn.click(
224
  fn=process_mvm2_pipeline,
225
  inputs=[input_img, enhance_toggle],
226
+ outputs=[preview_output, canvas_latex, signal_gauges, calib_bar_html, trace_html, download_btn, flow_view]
227
  )
228
 
229
  if __name__ == "__main__":
flow_module.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def generate_flow_html(active_phase="idle"):
2
+ """
3
+ Generates animated SVG for the MVM² Architecture Flow.
4
+ Phases: 'idle', 'enhance', 'ocr', 'reasoning', 'verification', 'consensus', 'success'
5
+ """
6
+
7
+ # Define colors
8
+ bg_color = "#1e293b"
9
+ accent = "#6366f1"
10
+ success = "#10b981"
11
+ text = "#94a3b8"
12
+
13
+ # Pulse animation logic
14
+ def get_pulse(phase):
15
+ return 'active-pulse' if active_phase == phase else ''
16
+
17
+ def get_node_style(phase):
18
+ if active_phase == 'success': return 'stroke: #10b981; filter: drop-shadow(0 0 8px #10b981);'
19
+ if active_phase == phase: return f'stroke: {accent}; filter: drop-shadow(0 0 8px {accent});'
20
+ return 'stroke: rgba(255,255,255,0.1);'
21
+
22
+ html = f"""
23
+ <div class="glass-card" style="width: 100%; height: 400px; display: flex; justify-content: center; align-items: center; overflow: hidden; position: relative;">
24
+ <svg width="800" height="350" viewBox="0 0 800 350" preserveAspectRatio="xMidYMid meet">
25
+ <!-- Definitions for markers and gradients -->
26
+ <defs>
27
+ <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="0" refY="3.5" orient="auto">
28
+ <polygon points="0 0, 10 3.5, 0 7" fill="{text}" />
29
+ </marker>
30
+ <linearGradient id="pulse-grad" x1="0%" y1="0%" x2="100%" y2="0%">
31
+ <stop offset="0%" stop-color="transparent" />
32
+ <stop offset="50%" stop-color="{accent}" />
33
+ <stop offset="100%" stop-color="transparent" />
34
+ </linearGradient>
35
+ </defs>
36
+
37
+ <!-- CONNECTIONS -->
38
+ <!-- Enhance to OCR -->
39
+ <path d="M100 175 H200" class="flow-line {get_pulse('enhance')}" stroke="{text}" stroke-width="2" marker-end="url(#arrowhead)" />
40
+
41
+ <!-- OCR to Reasoning -->
42
+ <path d="M300 175 H400" class="flow-line {get_pulse('ocr')}" stroke="{text}" stroke-width="2" marker-end="url(#arrowhead)" />
43
+
44
+ <!-- Reasoning to Consensus (4 Parallel) -->
45
+ <path d="M500 100 Q 550 175 600 175" class="flow-line {get_pulse('reasoning')}" stroke="{text}" stroke-width="1.5" />
46
+ <path d="M500 150 Q 550 175 600 175" class="flow-line {get_pulse('reasoning')}" stroke="{text}" stroke-width="1.5" />
47
+ <path d="M500 200 Q 550 175 600 175" class="flow-line {get_pulse('reasoning')}" stroke="{text}" stroke-width="1.5" />
48
+ <path d="M500 250 Q 550 175 600 175" class="flow-line {get_pulse('reasoning')}" stroke="{text}" stroke-width="1.5" />
49
+
50
+ <!-- Symbolic Bridge -->
51
+ <path d="M450 300 Q 450 250 450 250" class="flow-line {get_pulse('verification')}" stroke="{success}" stroke-width="3" stroke-dasharray="5,5" />
52
+
53
+ <!-- NODES -->
54
+ <!-- 1. Input/Enhance -->
55
+ <rect x="20" y="140" width="80" height="70" rx="10" fill="{bg_color}" style="{get_node_style('enhance')}" />
56
+ <text x="60" y="180" text-anchor="middle" fill="white" font-size="12">ENHANCE</text>
57
+
58
+ <!-- 2. OCR Module -->
59
+ <circle cx="250" cy="175" r="45" fill="{bg_color}" style="{get_node_style('ocr')}" />
60
+ <text x="250" y="180" text-anchor="middle" fill="white" font-size="12">OCR</text>
61
+
62
+ <!-- 3. Reasoning Agents (Parallel) -->
63
+ <g class="{'thinking' if active_phase == 'reasoning' else ''}">
64
+ <circle cx="450" cy="80" r="25" fill="{bg_color}" style="{get_node_style('reasoning')}" />
65
+ <circle cx="450" cy="140" r="25" fill="{bg_color}" style="{get_node_style('reasoning')}" />
66
+ <circle cx="450" cy="200" r="25" fill="{bg_color}" style="{get_node_style('reasoning')}" />
67
+ <circle cx="450" cy="260" r="25" fill="{bg_color}" style="{get_node_style('reasoning')}" />
68
+ <text x="450" y="45" text-anchor="middle" fill="{text}" font-size="10">REASONING</text>
69
+ </g>
70
+
71
+ <!-- 4. Verification Bridge (SymPy) -->
72
+ <rect x="400" y="300" width="100" height="40" rx="5" fill="{bg_color}" style="{get_node_style('verification')}" />
73
+ <text x="450" y="325" text-anchor="middle" fill="{success}" font-size="10" font-weight="bold">SYMPY CORE</text>
74
+
75
+ <!-- 5. Consensus -->
76
+ <polygon points="650,125 750,175 650,225" fill="{bg_color}" style="{get_node_style('consensus')}" />
77
+ <text x="680" y="180" text-anchor="middle" fill="white" font-size="12">CONSENSUS</text>
78
+ </svg>
79
+
80
+ <div style="position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); font-size: 0.8em; color: {text};">
81
+ Current Stage: <span style="color: {accent if active_phase != 'success' else success}; font-weight: bold; text-transform: uppercase;">{active_phase}</span>
82
+ </div>
83
+ </div>
84
+ """
85
+ return html
theme.css CHANGED
@@ -118,6 +118,39 @@ h2 { font-weight: 600; color: var(--text-main); }
118
  border-left: 4px solid var(--primary) !important;
119
  }
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  /* Gradio Overrides */
122
  .stButton button { border-radius: 10px !important; }
123
  .stMarkdown { color: var(--text-main) !important; }
 
118
  border-left: 4px solid var(--primary) !important;
119
  }
120
 
121
+ /* Architecture Flow Animations */
122
+ .flow-line {
123
+ stroke-dasharray: 1000;
124
+ stroke-dashoffset: 1000;
125
+ animation: none;
126
+ }
127
+
128
+ .active-pulse {
129
+ stroke-dashoffset: 0;
130
+ animation: pulse-flow 2s infinite linear;
131
+ stroke: var(--primary) !important;
132
+ opacity: 1;
133
+ }
134
+
135
+ @keyframes pulse-flow {
136
+ 0% { stroke-dashoffset: 1000; opacity: 0.3; }
137
+ 50% { opacity: 1; }
138
+ 100% { stroke-dashoffset: 0; opacity: 0.3; }
139
+ }
140
+
141
+ .thinking circle {
142
+ animation: thinking-pulse 1.5s infinite ease-in-out;
143
+ }
144
+
145
+ @keyframes thinking-pulse {
146
+ 0%, 100% { transform: scale(1); opacity: 0.8; }
147
+ 50% { transform: scale(1.1); opacity: 1; filter: brightness(1.2); }
148
+ }
149
+
150
+ .thinking {
151
+ transform-origin: 450px 175px;
152
+ }
153
+
154
  /* Gradio Overrides */
155
  .stButton button { border-radius: 10px !important; }
156
  .stMarkdown { color: var(--text-main) !important; }