from fasthtml.common import *
def PageLayout(title: str, content: list):
"""
The Base Layout.
Injects PicoCSS (Styling), PrismJS (Syntax Highlight), and HTMX (Interactivity).
"""
return Html(
Head(
Title(title),
# 1. PicoCSS: Semantic minimalist framework
Link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/@picocss/pico@latest/css/pico.min.css"),
# 2. HTMX (CRITICAL FIX: Prevents page reloads)
Script(src="https://unpkg.com/htmx.org@1.9.10"),
# 3. PrismJS: For beautiful JSON highlighting
Link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css"),
Script(src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"),
Script(src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-json.min.js"),
# Custom Styles
Style("""
body { max-width: 900px; margin: 0 auto; padding: 20px; background-color: #11191f; }
.json-box { border-radius: 8px; overflow: hidden; margin-top: 20px; }
h1 { color: #00E5FF; }
button.contrast { background-color: #00E5FF; border-color: #00E5FF; color: black; font-weight: bold; }
.error-box { background: #3d1a1a; color: #ff8080; padding: 15px; border-radius: 8px; border: 1px solid #ff4d4d; }
""")
),
Body(
Header(
H1("🛡️ Structura"),
P("The Unbreakable Data Architect", style="opacity: 0.7;"),
style="border-bottom: 1px solid #333; padding-bottom: 20px; margin-bottom: 40px;"
),
Main(*content),
Footer(
P("Powered by PydanticAI & Gemini 2.5", style="text-align: center; opacity: 0.5; font-size: 0.8rem; margin-top: 50px;")
)
)
)
# ... (Rest of components.py remains the same)
def HeroSection():
return Div(
H2("Turn Chaos into Structure"),
P("Paste messy emails, invoices, or resumes below. Get guaranteed, type-safe JSON back."),
style="margin-bottom: 30px;"
)
def ExtractionForm():
"""
The Interactive Form.
Uses HTMX (hx-post) to swap the result area without a page reload.
"""
return Form(
Label("Raw Input Data"),
Textarea(
name="text_input",
placeholder="e.g. Invoice #909 from CloudFix for $500...",
rows=8,
style="font-family: monospace; background: #0b0f13; color: white; border: 1px solid #333;"
),
Grid(
Label("Target Schema",
Select(
Option("Invoice Extraction", value="invoice"),
Option("Resume Parsing", value="resume"),
Option("Generic Data", value="generic"),
name="schema_type"
)
),
# Empty div for grid balance or future features
Div()
),
Button("Extract Structure ⚡", cls="contrast", type="submit"),
# HTMX Configuration
hx_post="/extract",
hx_target="#result-area",
hx_swap="innerHTML",
hx_indicator="#loading"
)
def LoadingIndicator():
return Div("⚙️ AI is processing...", id="loading", cls="htmx-indicator", style="color: #00E5FF; margin-top: 10px;")
def SuccessDisplay(json_str: str):
return Div(
H4("✅ Validated Output", style="color: #4ade80; margin-bottom: 10px;"),
Div(
Pre(Code(json_str, cls="language-json")),
cls="json-box"
),
P("Schema Verified by PydanticAI", style="color: grey; font-size: 0.8rem; margin-top: 10px; text-align: right;")
)
def ErrorDisplay(error_msg: str):
return Div(
H4("❌ Extraction Failed"),
P(error_msg),
cls="error-box"
)