File size: 6,085 Bytes
575d372 8eac7f1 575d372 8eac7f1 575d372 8eac7f1 575d372 8eac7f1 575d372 8eac7f1 575d372 8eac7f1 575d372 8eac7f1 575d372 8eac7f1 575d372 8eac7f1 575d372 8eac7f1 575d372 8eac7f1 575d372 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | def generate_flow_html(active_phase="idle"):
"""
Generates animated SVG for the MVM² Architecture Flow.
Phases: 'idle', 'enhance', 'ocr', 'reasoning', 'heuristics', 'verification', 'consensus', 'success'
"""
# Define colors
bg_color = "#1e293b"
accent = "#e63946" # Red to match local dashboard theme
success = "#16a34a"
text = "#94a3b8"
# Pulse animation logic
def get_pulse(phase):
return 'active-pulse' if active_phase == phase else ''
def get_node_style(phase):
if active_phase == 'success': return f'stroke: {success}; filter: drop-shadow(0 0 8px {success});'
if active_phase == phase: return f'stroke: {accent}; filter: drop-shadow(0 0 8px {accent});'
return 'stroke: rgba(255,255,255,0.1);'
html = f"""
<div style="width: 100%; height: 400px; display: flex; justify-content: center; align-items: center; overflow: hidden; position: relative; background: rgba(30, 30, 30, 0.6); border-radius: 12px; border: 1px solid rgba(255,255,255,0.05);">
<svg width="800" height="350" viewBox="0 0 800 350" preserveAspectRatio="xMidYMid meet">
<!-- Definitions for markers and gradients -->
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="0" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="{text}" />
</marker>
<style>
.flow-line {{ stroke-dasharray: 1000; stroke-dashoffset: 1000; }}
.active-pulse {{ stroke-dashoffset: 0; animation: pulse-flow 2s infinite linear; stroke: {accent} !important; opacity: 1; }}
@keyframes pulse-flow {{ 0% {{ stroke-dashoffset: 1000; opacity: 0.3; }} 50% {{ opacity: 1; }} 100% {{ stroke-dashoffset: 0; opacity: 0.3; }} }}
.thinking circle {{ animation: thinking-pulse 1.5s infinite ease-in-out; }}
@keyframes thinking-pulse {{ 0%, 100% {{ transform: scale(1); opacity: 0.8; }} 50% {{ transform: scale(1.1); opacity: 1; filter: brightness(1.2); }} }}
.thinking {{ transform-origin: 450px 175px; }}
</style>
</defs>
<!-- CONNECTIONS -->
<!-- Enhance to OCR -->
<path d="M100 175 H200" class="flow-line {get_pulse('enhance')}" stroke="{text}" stroke-width="2" marker-end="url(#arrowhead)" />
<!-- OCR to Reasoning -->
<path d="M300 175 H400" class="flow-line {get_pulse('ocr')}" stroke="{text}" stroke-width="2" marker-end="url(#arrowhead)" />
<!-- Reasoning to Consensus (4 Parallel) -->
<path d="M500 100 Q 525 100 550 175" class="flow-line {get_pulse('reasoning')}" stroke="{text}" stroke-width="1.5" />
<path d="M500 150 Q 525 150 550 175" class="flow-line {get_pulse('reasoning')}" stroke="{text}" stroke-width="1.5" />
<path d="M500 200 Q 525 200 550 175" class="flow-line {get_pulse('reasoning')}" stroke="{text}" stroke-width="1.5" />
<path d="M500 250 Q 525 250 550 175" class="flow-line {get_pulse('reasoning')}" stroke="{text}" stroke-width="1.5" />
<!-- Heuristics to Consensus -->
<path d="M600 175 H640" class="flow-line {get_pulse('heuristics')}" stroke="{accent}" stroke-width="2" marker-end="url(#arrowhead)" />
<!-- Symbolic Bridge -->
<path d="M450 300 Q 450 250 450 250" class="flow-line {get_pulse('verification')}" stroke="{success}" stroke-width="3" stroke-dasharray="5,5" />
<!-- NODES -->
<!-- 1. Input/Enhance -->
<rect x="20" y="140" width="80" height="70" rx="10" fill="{bg_color}" style="{get_node_style('enhance')}" />
<text x="60" y="180" text-anchor="middle" fill="white" font-size="10" font-weight="600">ENHANCE</text>
<!-- 2. OCR Module -->
<circle cx="250" cy="175" r="45" fill="{bg_color}" style="{get_node_style('ocr')}" />
<text x="250" y="180" text-anchor="middle" fill="white" font-size="10" font-weight="600">OCR</text>
<!-- 3. Reasoning Agents (Parallel) -->
<g class="{'thinking' if active_phase == 'reasoning' else ''}">
<circle cx="450" cy="80" r="25" fill="{bg_color}" style="{get_node_style('reasoning')}" />
<circle cx="450" cy="140" r="25" fill="{bg_color}" style="{get_node_style('reasoning')}" />
<circle cx="450" cy="200" r="25" fill="{bg_color}" style="{get_node_style('reasoning')}" />
<circle cx="450" cy="260" r="25" fill="{bg_color}" style="{get_node_style('reasoning')}" />
<text x="450" y="45" text-anchor="middle" fill="{text}" font-size="10">REASONING</text>
</g>
<!-- 4. Heuristics Module -->
<rect x="550" y="150" width="50" height="50" rx="5" fill="{bg_color}" style="{get_node_style('heuristics')}" />
<text x="575" y="180" text-anchor="middle" fill="white" font-size="8" font-weight="600">FILTER</text>
<!-- 5. Verification Bridge (SymPy) -->
<rect x="400" y="300" width="100" height="40" rx="5" fill="{bg_color}" style="{get_node_style('verification')}" />
<text x="450" y="325" text-anchor="middle" fill="{success}" font-size="10" font-weight="bold">SYMPY CORE</text>
<!-- 6. Consensus -->
<polygon points="650,125 750,175 650,225" fill="{bg_color}" style="{get_node_style('consensus')}" />
<text x="680" y="180" text-anchor="middle" fill="white" font-size="10" font-weight="600">CONSENSUS</text>
</svg>
<div style="position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); font-size: 0.8em; color: {text};">
Current Stage: <span style="color: {accent if active_phase != 'success' else success}; font-weight: bold; text-transform: uppercase;">{active_phase}</span>
</div>
</div>
"""
return html
|