Owadokun Tosin Tobi commited on
Create components.py
Browse files- app/components.py +73 -0
app/components.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from fasthtml.common import *
|
| 2 |
+
|
| 3 |
+
def Layout(title, content):
|
| 4 |
+
"""Global Page Layout with PicoCSS"""
|
| 5 |
+
return Html(
|
| 6 |
+
Head(
|
| 7 |
+
Title(title),
|
| 8 |
+
# PicoCSS: Minimalist Semantic CSS
|
| 9 |
+
Link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/@picocss/pico@latest/css/pico.min.css"),
|
| 10 |
+
# PrismJS: For beautiful JSON Syntax Highlighting
|
| 11 |
+
Link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css"),
|
| 12 |
+
Script(src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"),
|
| 13 |
+
Script(src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-json.min.js"),
|
| 14 |
+
Style("body { max-width: 800px; margin: 0 auto; padding: 20px; }")
|
| 15 |
+
),
|
| 16 |
+
Body(
|
| 17 |
+
Header(
|
| 18 |
+
H1("🛡️ Structura", style="color: #00E5FF; margin-bottom: 0;"),
|
| 19 |
+
P("The Unbreakable Data Architect", style="opacity: 0.7;"),
|
| 20 |
+
style="border-bottom: 1px solid #333; padding-bottom: 20px; margin-bottom: 40px;"
|
| 21 |
+
),
|
| 22 |
+
Main(content),
|
| 23 |
+
Footer(
|
| 24 |
+
P("Powered by PydanticAI & Gemini 2.5", style="text-align: center; opacity: 0.5; font-size: 0.8rem;")
|
| 25 |
+
)
|
| 26 |
+
)
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
def InputForm():
|
| 30 |
+
"""The HTMX-powered Input Form"""
|
| 31 |
+
return Form(
|
| 32 |
+
Label("Raw Input Data", cls="label"),
|
| 33 |
+
Textarea(
|
| 34 |
+
name="text_input",
|
| 35 |
+
placeholder="Paste messy text here (Email, Invoice, Job Post)...",
|
| 36 |
+
rows=8,
|
| 37 |
+
style="font-family: monospace;"
|
| 38 |
+
),
|
| 39 |
+
|
| 40 |
+
Label("Target Schema", cls="label"),
|
| 41 |
+
Select(
|
| 42 |
+
Option("Invoice Extraction", value="invoice"),
|
| 43 |
+
Option("Resume Parsing", value="resume"),
|
| 44 |
+
Option("Email Summary", value="email"),
|
| 45 |
+
name="schema_type"
|
| 46 |
+
),
|
| 47 |
+
|
| 48 |
+
Button("Extract Structure ⚡", cls="contrast", type="submit"),
|
| 49 |
+
|
| 50 |
+
# HTMX Magic: Swaps the result div without reloading page
|
| 51 |
+
hx_post="/extract",
|
| 52 |
+
hx_target="#result-area",
|
| 53 |
+
hx_swap="innerHTML"
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
def ResultDisplay(json_data=None, error=None):
|
| 57 |
+
"""Renders the output or error state"""
|
| 58 |
+
if error:
|
| 59 |
+
return Div(
|
| 60 |
+
H4("❌ Extraction Failed"),
|
| 61 |
+
P(error),
|
| 62 |
+
style="background: #3d1a1a; color: #ff8080; padding: 15px; border-radius: 8px; border: 1px solid #ff4d4d;"
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
if json_data:
|
| 66 |
+
return Div(
|
| 67 |
+
H4("✅ Validated JSON Output"),
|
| 68 |
+
# Pre/Code blocks triggered PrismJS highlighting
|
| 69 |
+
Pre(Code(json_data, cls="language-json")),
|
| 70 |
+
P("Schema validation passed.", style="color: #00E5FF; font-size: 0.8rem; margin-top: 10px;")
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
+
return Div(id="result-area") # Empty placeholder
|