fhirflame / index.html
grasant's picture
Fix Space startup and credential-free demo
94d986f verified
Raw
History Blame Contribute Delete
90.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FhirFlame - Medical AI Platform for FHIR-Compliant Document Processing</title>
<meta name="description" content="Open-source medical AI platform with MCP integration, FHIR R4/R5 compliance, multi-provider AI routing, and agent-to-agent communication. Prototype for development and testing.">
<meta name="theme-color" content="#111111">
<meta name="msapplication-TileColor" content="#111111">
<link rel="icon" type="image/svg+xml" href="fhirflame_logo.svg">
<link rel="icon" type="image/png" sizes="32x32" href="static/fhirflame_logo.png">
<link rel="icon" type="image/x-icon" href="static/favicon.ico">
<link rel="apple-touch-icon" sizes="180x180" href="static/fhirflame_logo.png">
<link rel="manifest" href="static/site.webmanifest">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-deep: #111111;
--bg-surface: #191919;
--bg-elevated: #212121;
--border: rgba(255,255,255,0.08);
--border-hover: rgba(255,255,255,0.16);
--accent: #DC2626;
--accent-soft: rgba(220,38,38,0.12);
--trust: #0EA5E9;
--trust-soft: rgba(14,165,233,0.12);
--success: #10B981;
--success-soft: rgba(16,185,129,0.12);
--text: #F0F0F0;
--text-secondary: #A0A0A0;
--text-muted: #6B6B6B;
--cta-metal: linear-gradient(105deg, #727985 0%, #AAB0BA 24%, #F5F7FA 48%, #DC2626 54%, #B8BEC8 72%, #727985 100%);
--cta-red: #8F1018;
--cta-red-soft: rgba(143,16,24,0.72);
--radius: 12px;
--radius-lg: 16px;
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: var(--bg-deep);
color: var(--text);
line-height: 1.6;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
}
.container {
max-width: 1140px;
margin: 0 auto;
padding: 0 24px;
}
/* ── Navbar ── */
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
background: rgba(12,12,12,0.88);
backdrop-filter: blur(20px) saturate(130%);
-webkit-backdrop-filter: blur(20px) saturate(130%);
border-bottom: 1px solid rgba(255,255,255,0.06);
box-shadow: 0 12px 32px rgba(0,0,0,0.18);
}
.navbar::after {
content: '';
position: absolute;
right: 0;
bottom: -1px;
left: 0;
height: 1px;
background: linear-gradient(90deg, transparent 8%, rgba(220,38,38,0.7) 32%, rgba(240,240,240,0.22) 50%, rgba(14,165,233,0.42) 68%, transparent 92%);
opacity: 0.55;
}
.navbar .container {
display: flex;
align-items: center;
justify-content: space-between;
height: 72px;
}
.nav-brand {
display: flex;
align-items: center;
text-decoration: none;
color: var(--text);
transition: opacity 0.2s ease, transform 0.2s ease;
}
.nav-brand:hover { opacity: 0.86; transform: translateY(-1px); }
.nav-brand img {
height: 40px;
width: auto;
filter: drop-shadow(0 0 12px rgba(220,38,38,0.12));
}
.nav-links {
display: flex;
align-items: center;
gap: 28px;
list-style: none;
}
.nav-links a {
color: var(--text-secondary);
text-decoration: none;
font-size: 0.74rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
transition: color 0.2s ease;
}
.nav-links a:hover { color: var(--text); }
.nav-links a:not(.nav-cta) {
position: relative;
padding: 27px 0 24px;
}
.nav-links a:not(.nav-cta)::after {
content: '';
position: absolute;
right: 0;
bottom: 18px;
left: 0;
height: 1px;
background: linear-gradient(90deg, var(--accent), var(--trust));
transform: scaleX(0);
transform-origin: right;
transition: transform 0.25s ease;
}
.nav-links a:not(.nav-cta):hover::after {
transform: scaleX(1);
transform-origin: left;
}
.nav-cta {
position: relative;
overflow: hidden;
background: linear-gradient(120deg, #7F1118, var(--accent) 52%, #A3131C);
color: #fff !important;
padding: 10px 20px;
clip-path: polygon(8px 0, 100% 0, calc(100% - 8px) 100%, 0 100%);
box-shadow: 0 8px 22px rgba(220,38,38,0.2);
transition: filter 0.2s ease, transform 0.2s ease;
}
.nav-cta:hover {
filter: brightness(1.12);
transform: translateY(-1px);
}
.nav-toggle {
display: none;
background: none;
border: none;
color: var(--text);
font-size: 1.5rem;
cursor: pointer;
}
/* ── Disclaimer ── */
.disclaimer {
margin-top: 72px;
background: var(--bg-elevated);
border-bottom: 1px solid var(--border);
text-align: center;
padding: 10px 24px;
font-size: 0.8rem;
color: var(--text-muted);
letter-spacing: 0.02em;
}
.disclaimer strong {
color: var(--text-secondary);
font-weight: 600;
}
/* ── Hero ── */
.hero {
padding: 120px 0 80px;
text-align: center;
position: relative;
}
.hero::before {
content: '';
position: absolute;
top: 0; left: 50%;
transform: translateX(-50%);
width: 800px;
height: 600px;
background: radial-gradient(ellipse, rgba(220,38,38,0.06) 0%, transparent 70%);
pointer-events: none;
}
.hero-content {
position: relative;
z-index: 2;
}
.hero .logo {
width: 200px;
height: auto;
margin: 0 auto 32px;
display: block;
}
.hero h1 {
font-size: 3rem;
font-weight: 700;
line-height: 1.15;
margin-bottom: 20px;
color: var(--text);
}
.hero h1 span {
background: linear-gradient(135deg, var(--text), var(--trust));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-subtitle {
font-size: 1.15rem;
color: var(--text-secondary);
max-width: 620px;
margin: 0 auto 40px;
line-height: 1.7;
}
.trust-badges {
display: flex;
justify-content: center;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 40px;
}
.trust-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
border-radius: 0;
font-size: 0.8rem;
font-weight: 500;
border: 1px solid var(--border);
color: var(--text-secondary);
background: var(--bg-surface);
}
.trust-badge .dot {
width: 6px;
height: 6px;
border-radius: 50%;
display: inline-block;
}
.trust-badge .dot--red { background: var(--accent); }
.trust-badge .dot--blue { background: var(--trust); }
.trust-badge .dot--green { background: var(--success); }
.hero-actions {
display: flex;
gap: 16px;
justify-content: center;
flex-wrap: wrap;
}
.demo-requirement {
max-width: 620px;
margin: 14px auto 0;
color: var(--text-muted);
font-size: 0.85rem;
line-height: 1.5;
}
.demo-requirement a {
color: var(--trust);
font-weight: 600;
}
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 14px 28px;
font-size: 0.95rem;
font-weight: 600;
text-decoration: none;
border-radius: 10px;
transition: all 0.2s ease;
border: 1px solid transparent;
cursor: pointer;
}
.btn-primary {
background: var(--accent);
color: #fff;
}
.btn-primary:hover {
background: #B91C1C;
transform: translateY(-1px);
box-shadow: 0 8px 24px rgba(220,38,38,0.25);
}
/* HelloFibro-inspired expanding demo CTA */
.demo-cta {
position: relative;
isolation: isolate;
justify-content: flex-start;
min-height: 50px;
padding: 14px 20px 14px 16px;
overflow: hidden;
border: 0;
border-radius: 0;
background: transparent;
color: #D5D8DE;
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
box-shadow: none;
}
.demo-cta::before {
content: '';
position: absolute;
top: 50%;
left: 11px;
z-index: -1;
width: 35px;
height: 35px;
transform: translateY(-50%) rotate(45deg);
background:
linear-gradient(90deg, transparent, rgba(255,255,255,0.05) 25%, rgba(255,255,255,0.18) 50%, rgba(255,255,255,0.05) 75%, transparent),
var(--cta-red-soft);
background-size: 200% 100%, 100% 100%;
animation: ctaShimmer 3.2s ease-in-out infinite;
transition: left 0.3s ease, width 0.3s ease, height 0.3s ease, transform 0.3s ease, clip-path 0.3s ease;
}
.demo-cta::after {
content: '›';
position: relative;
z-index: 1;
margin-left: 2px;
font-size: 1rem;
line-height: 1;
transition: transform 0.25s ease;
}
.demo-cta span,
.demo-cta::after {
background: var(--cta-metal);
background-size: 280% 100%;
color: transparent;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
animation: ctaMetal 3.8s ease-in-out infinite;
}
.demo-cta:hover {
background: transparent;
color: #fff;
transform: translateY(-1px);
box-shadow: none;
}
.demo-cta:hover::before {
left: 0;
width: 100%;
height: 100%;
transform: translateY(-50%) rotate(0);
clip-path: polygon(12px 0, 100% 0, calc(100% - 12px) 100%, 0 100%);
background:
linear-gradient(90deg, transparent, rgba(255,255,255,0.06) 25%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.06) 75%, transparent),
var(--cta-red);
background-size: 200% 100%, 100% 100%;
animation: ctaShimmer 1.4s ease-in-out infinite;
}
.demo-cta:hover span,
.demo-cta:hover::after {
background: none;
color: #fff;
-webkit-text-fill-color: #fff;
animation: none;
}
.demo-cta:hover::after { transform: translateX(3px); }
.btn-outline {
background: transparent;
color: var(--text);
border-color: var(--border-hover);
}
.btn-outline:hover {
background: var(--bg-elevated);
border-color: var(--text-muted);
}
/* ── Metrics ── */
.metrics {
padding: 60px 0;
border-top: 1px solid var(--border);
border-bottom: 1px solid var(--border);
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 24px;
}
.metric {
text-align: center;
}
.metric-value {
font-size: 2.25rem;
font-weight: 700;
color: var(--text);
margin-bottom: 6px;
line-height: 1;
}
.metric-label {
font-size: 0.85rem;
color: var(--text-muted);
line-height: 1.4;
}
/* ── Section shared ── */
.section {
padding: 96px 0;
}
.section--alt {
background: var(--bg-surface);
}
.section-header {
text-align: center;
margin-bottom: 56px;
}
.section-label {
display: inline-block;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--trust);
margin-bottom: 12px;
}
.section-title {
font-size: 2rem;
font-weight: 700;
color: var(--text);
margin-bottom: 16px;
}
.section-desc {
font-size: 1rem;
color: var(--text-secondary);
max-width: 560px;
margin: 0 auto;
line-height: 1.6;
}
/* ── Capabilities ── */
.cap-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.cap-card {
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 32px 28px;
transition: border-color 0.2s, box-shadow 0.2s;
}
.cap-card:hover {
border-color: var(--border-hover);
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
}
.cap-icon {
width: 40px;
height: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.1rem;
margin-bottom: 20px;
font-weight: 700;
}
.cap-icon--red { background: var(--accent-soft); color: var(--accent); }
.cap-icon--blue { background: var(--trust-soft); color: var(--trust); }
.cap-icon--green { background: var(--success-soft); color: var(--success); }
.cap-card h3 {
font-size: 1.1rem;
font-weight: 600;
color: var(--text);
margin-bottom: 10px;
}
.cap-card p {
font-size: 0.9rem;
color: var(--text-secondary);
line-height: 1.6;
}
.cap-list {
margin-top: 14px;
list-style: none;
font-size: 0.82rem;
color: var(--text-muted);
}
.cap-list li {
padding: 3px 0;
}
.cap-list li::before {
content: '';
display: inline-block;
width: 4px;
height: 4px;
border-radius: 50%;
background: var(--text-muted);
margin-right: 8px;
vertical-align: middle;
}
/* ── Pipeline ── */
.pipeline-track {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0;
position: relative;
}
.pipeline-track::before {
content: '';
position: absolute;
top: 28px;
left: 12.5%;
right: 12.5%;
height: 2px;
background: var(--border-hover);
}
.pipeline-step {
text-align: center;
position: relative;
padding: 0 16px;
}
.pipeline-num {
width: 56px;
height: 56px;
border-radius: 50%;
background: var(--bg-elevated);
border: 2px solid var(--border-hover);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 20px;
font-weight: 700;
font-size: 1rem;
color: var(--trust);
position: relative;
z-index: 2;
}
.pipeline-step h4 {
font-size: 0.95rem;
font-weight: 600;
color: var(--text);
margin-bottom: 8px;
}
.pipeline-detail {
font-size: 0.82rem;
color: var(--text-muted);
line-height: 1.5;
}
/* ── Architecture ── */
.arch-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.arch-node {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px;
text-align: center;
transition: border-color 0.2s;
}
.arch-node:hover { border-color: var(--border-hover); }
.arch-node-label {
font-size: 0.95rem;
font-weight: 600;
color: var(--text);
margin-bottom: 4px;
}
.arch-node-tech {
font-size: 0.82rem;
color: var(--text-secondary);
}
.arch-node-port {
display: inline-block;
margin-top: 8px;
font-size: 0.72rem;
font-weight: 500;
color: var(--text-muted);
background: rgba(255,255,255,0.04);
padding: 2px 10px;
border-radius: 10px;
}
/* ── Quick Start ── */
.qs-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 28px;
}
.qs-card {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 32px;
}
.qs-card h3 {
font-size: 1.1rem;
font-weight: 600;
color: var(--text);
margin-bottom: 4px;
}
.qs-label {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-muted);
margin-bottom: 20px;
}
.qs-card pre {
background: rgba(0,0,0,0.35);
border: 1px solid var(--border);
border-radius: 10px;
padding: 20px;
color: var(--text-secondary);
font-size: 0.85rem;
line-height: 1.7;
overflow-x: auto;
white-space: pre;
font-family: 'SF Mono', 'Fira Code', 'Courier New', monospace;
}
.qs-ports {
width: 100%;
margin-top: 16px;
border-collapse: collapse;
}
.qs-ports td {
padding: 7px 0;
border-bottom: 1px solid var(--border);
font-size: 0.85rem;
}
.qs-ports td:first-child {
color: var(--text);
font-weight: 500;
}
.qs-ports td:last-child {
color: var(--text-muted);
font-family: 'SF Mono', 'Fira Code', 'Courier New', monospace;
text-align: right;
}
.qs-note {
margin-top: 16px;
font-size: 0.8rem;
color: var(--text-muted);
line-height: 1.5;
}
.qs-note code {
background: rgba(255,255,255,0.06);
padding: 1px 6px;
border-radius: 4px;
font-size: 0.78rem;
}
/* ── Providers ── */
.prov-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.prov-card {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px;
transition: border-color 0.2s;
}
.prov-card:hover { border-color: var(--border-hover); }
.prov-card h4 {
font-size: 0.95rem;
font-weight: 600;
color: var(--text);
margin-bottom: 8px;
}
.prov-card p {
font-size: 0.82rem;
color: var(--text-secondary);
line-height: 1.5;
}
.prov-card code {
background: rgba(255,255,255,0.06);
padding: 1px 6px;
border-radius: 4px;
font-size: 0.78rem;
color: var(--text-secondary);
}
.prov-tag {
display: inline-block;
margin-top: 10px;
font-size: 0.7rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
padding: 3px 10px;
border-radius: 6px;
}
.prov-tag--free { background: var(--success-soft); color: var(--success); }
.prov-tag--paid { background: var(--trust-soft); color: var(--trust); }
/* ── Security ── */
.sec-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
.sec-card {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 32px;
}
.sec-card h3 {
font-size: 1.05rem;
font-weight: 600;
color: var(--text);
margin-bottom: 14px;
}
.sec-list {
list-style: none;
font-size: 0.85rem;
color: var(--text-secondary);
line-height: 1.7;
}
.sec-list li::before {
content: '\2713';
margin-right: 8px;
color: var(--success);
font-weight: 700;
}
/* ── CTA ── */
.cta-section {
padding: 96px 0;
text-align: center;
background: linear-gradient(180deg, var(--bg-surface) 0%, var(--bg-deep) 100%);
}
.cta-section h2 {
font-size: 2rem;
font-weight: 700;
color: var(--text);
margin-bottom: 14px;
}
.cta-section p {
color: var(--text-secondary);
margin-bottom: 36px;
font-size: 1rem;
}
.cta-actions {
display: flex;
gap: 16px;
justify-content: center;
flex-wrap: wrap;
}
.cta-actions .btn-outline {
border-radius: 0;
}
/* ── Footer ── */
.footer {
padding: 56px 0 40px;
border-top: 1px solid var(--border);
}
.footer-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 40px;
margin-bottom: 40px;
}
.footer-col h4 {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
margin-bottom: 16px;
}
.footer-col ul {
list-style: none;
}
.footer-col li { margin-bottom: 8px; }
.footer-col a {
color: var(--text-secondary);
text-decoration: none;
font-size: 0.875rem;
transition: color 0.2s;
}
.footer-col a:hover { color: var(--text); }
.footer-bottom {
border-top: 1px solid var(--border);
padding-top: 24px;
text-align: center;
font-size: 0.8rem;
color: var(--text-muted);
}
.footer-bottom strong { color: var(--text-secondary); font-weight: 600; }
/* ── Responsive ── */
@media (max-width: 1024px) {
.cap-grid { grid-template-columns: repeat(2, 1fr); }
.pipeline-track { grid-template-columns: repeat(2, 1fr); gap: 32px; }
.pipeline-track::before { display: none; }
.arch-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
.nav-links { display: none; }
.nav-toggle { display: block; }
.nav-links.open {
display: flex;
flex-direction: column;
align-items: stretch;
position: absolute;
top: 72px;
left: 0;
right: 0;
background: rgba(12,12,12,0.98);
border-bottom: 1px solid var(--border);
padding: 18px 24px 22px;
gap: 4px;
}
.nav-links.open a:not(.nav-cta) {
display: block;
padding: 10px 0;
}
.nav-links.open a:not(.nav-cta)::after {
bottom: 5px;
}
.hero { padding: 96px 0 64px; }
.hero h1 { font-size: 2rem; }
.hero-subtitle { font-size: 1rem; }
.metrics-grid { grid-template-columns: repeat(3, 1fr); gap: 20px; }
.section { padding: 72px 0; }
.section-title { font-size: 1.6rem; }
.cap-grid,
.qs-grid,
.sec-grid,
.prov-grid,
.arch-grid { grid-template-columns: 1fr; }
.pipeline-track { grid-template-columns: 1fr; }
.footer-grid { grid-template-columns: 1fr; gap: 28px; }
}
/* ── Why / Value Prop ── */
.why-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24px;
}
.why-card {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 32px;
display: flex;
gap: 20px;
transition: border-color 0.2s;
}
.why-card:hover { border-color: var(--border-hover); }
.why-num {
width: 40px;
height: 40px;
min-width: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.1rem;
font-weight: 700;
}
.why-card h3 {
font-size: 1.05rem;
font-weight: 600;
color: var(--text);
margin-bottom: 8px;
}
.why-card p {
font-size: 0.88rem;
color: var(--text-secondary);
line-height: 1.6;
}
.why-card .arrow-label {
display: inline-block;
margin-top: 10px;
font-size: 0.78rem;
font-weight: 600;
color: var(--trust);
}
/* ── Use Cases ── */
.uc-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24px;
}
.uc-card {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 32px;
transition: border-color 0.2s, box-shadow 0.2s;
}
.uc-card:hover {
border-color: var(--border-hover);
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
}
.uc-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 14px;
}
.uc-icon {
width: 44px;
height: 44px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
}
.uc-card h3 {
font-size: 1.05rem;
font-weight: 600;
color: var(--text);
}
.uc-card > p {
font-size: 0.88rem;
color: var(--text-secondary);
line-height: 1.6;
margin-bottom: 14px;
}
.uc-flow {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
margin-top: 14px;
}
.uc-flow-step {
font-size: 0.75rem;
font-weight: 500;
color: var(--text-muted);
background: rgba(255,255,255,0.04);
padding: 4px 12px;
border-radius: 6px;
border: 1px solid var(--border);
white-space: nowrap;
}
.uc-flow-arrow {
color: var(--text-muted);
font-size: 0.7rem;
}
/* ── Formats ── */
.fmt-container {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 32px;
align-items: center;
}
.fmt-box {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 32px;
}
.fmt-box h3 {
font-size: 1.1rem;
font-weight: 600;
color: var(--text);
margin-bottom: 20px;
text-align: center;
}
.fmt-list {
list-style: none;
display: flex;
flex-direction: column;
gap: 10px;
}
.fmt-item {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 14px;
background: rgba(255,255,255,0.03);
border-radius: 8px;
border: 1px solid var(--border);
}
.fmt-item-icon {
width: 32px;
height: 32px;
min-width: 32px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.7rem;
font-weight: 700;
}
.fmt-item-text {
font-size: 0.88rem;
font-weight: 500;
color: var(--text);
}
.fmt-item-sub {
font-size: 0.78rem;
color: var(--text-muted);
font-weight: 400;
}
.fmt-arrow {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
color: var(--text-muted);
}
.fmt-arrow-line {
width: 60px;
height: 2px;
background: var(--border-hover);
position: relative;
}
.fmt-arrow-line::after {
content: '';
position: absolute;
right: -1px;
top: -4px;
border: 5px solid transparent;
border-left-color: var(--border-hover);
}
.fmt-arrow-label {
font-size: 0.7rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--trust);
}
/* ── Tech Stack ── */
.stack-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
}
.stack-group {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 24px;
}
.stack-group h4 {
font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-muted);
margin-bottom: 14px;
}
.stack-items {
display: flex;
flex-direction: column;
gap: 8px;
}
.stack-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.85rem;
color: var(--text-secondary);
}
.stack-dot {
width: 6px;
height: 6px;
border-radius: 50%;
min-width: 6px;
}
@media (max-width: 1024px) {
.stack-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
.why-grid,
.uc-grid { grid-template-columns: 1fr; }
.fmt-container { grid-template-columns: 1fr; gap: 16px; }
.fmt-arrow { transform: rotate(90deg); }
.stack-grid { grid-template-columns: 1fr; }
}
/* ── Video Demo ── */
.demo-video {
padding: 96px 0;
background: var(--bg-surface);
}
.video-wrapper {
position: relative;
max-width: 605px;
margin: 0 auto;
border-radius: var(--radius-lg);
overflow: hidden;
border: 1px solid var(--border);
box-shadow: 0 24px 64px rgba(0,0,0,0.4);
background: #000;
}
.video-wrapper video {
display: block;
width: 100%;
height: auto;
border-radius: var(--radius-lg);
cursor: pointer;
}
.video-wrapper .video-overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0,0,0,0.35);
cursor: pointer;
transition: background 0.3s;
border-radius: var(--radius-lg);
}
.video-wrapper .video-overlay:hover {
background: rgba(0,0,0,0.2);
}
.video-wrapper .video-overlay.hidden {
opacity: 0;
pointer-events: none;
transition: opacity 0.4s;
}
.play-btn {
width: 80px;
height: 80px;
border-radius: 50%;
background: rgba(220,38,38,0.9);
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.2s, box-shadow 0.2s;
box-shadow: 0 8px 32px rgba(220,38,38,0.3);
}
.play-btn:hover {
transform: scale(1.08);
box-shadow: 0 12px 40px rgba(220,38,38,0.4);
}
.play-btn svg {
width: 32px;
height: 32px;
fill: #fff;
margin-left: 4px;
}
/* ── Feature Deep-Dive ── */
.features-detail {
padding: 96px 0;
}
.fd-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 64px;
align-items: center;
}
.fd-grid--reverse {
direction: rtl;
}
.fd-grid--reverse > * {
direction: ltr;
}
.fd-content {
display: flex;
flex-direction: column;
gap: 16px;
}
.fd-label {
display: inline-block;
font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
padding: 4px 12px;
border-radius: 6px;
width: fit-content;
}
.fd-label--red { background: var(--accent-soft); color: var(--accent); }
.fd-label--blue { background: var(--trust-soft); color: var(--trust); }
.fd-label--green { background: var(--success-soft); color: var(--success); }
.fd-title {
font-size: 1.6rem;
font-weight: 700;
color: var(--text);
line-height: 1.3;
}
.fd-desc {
font-size: 0.95rem;
color: var(--text-secondary);
line-height: 1.7;
}
.fd-highlights {
display: flex;
flex-direction: column;
gap: 12px;
margin-top: 8px;
}
.fd-highlight {
display: flex;
align-items: flex-start;
gap: 12px;
font-size: 0.88rem;
color: var(--text-secondary);
line-height: 1.5;
}
.fd-highlight-icon {
width: 24px;
height: 24px;
min-width: 24px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.7rem;
font-weight: 700;
margin-top: 1px;
}
.fd-highlight-icon--red { background: var(--accent-soft); color: var(--accent); }
.fd-highlight-icon--blue { background: var(--trust-soft); color: var(--trust); }
.fd-highlight-icon--green { background: var(--success-soft); color: var(--success); }
.fd-visual {
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 32px;
position: relative;
overflow: hidden;
}
.fd-visual pre {
background: rgba(0,0,0,0.4);
border: 1px solid var(--border);
border-radius: 10px;
padding: 20px;
color: var(--text-secondary);
font-size: 0.8rem;
line-height: 1.6;
overflow-x: auto;
white-space: pre;
font-family: 'SF Mono', 'Fira Code', 'Courier New', monospace;
}
.fd-visual-label {
font-size: 0.7rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-muted);
margin-bottom: 12px;
}
.fd-stat-row {
display: flex;
gap: 16px;
margin-top: 16px;
}
.fd-stat {
flex: 1;
background: rgba(255,255,255,0.03);
border: 1px solid var(--border);
border-radius: 10px;
padding: 14px;
text-align: center;
}
.fd-stat-value {
font-size: 1.3rem;
font-weight: 700;
color: var(--text);
}
.fd-stat-label {
font-size: 0.72rem;
color: var(--text-muted);
margin-top: 2px;
}
@media (max-width: 768px) {
.fd-grid,
.fd-grid--reverse { grid-template-columns: 1fr; gap: 32px; }
.fd-grid--reverse { direction: ltr; }
.fd-title { font-size: 1.35rem; }
.video-wrapper { border-radius: var(--radius); }
.play-btn { width: 60px; height: 60px; }
.play-btn svg { width: 24px; height: 24px; }
}
/* ── Animations ── */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes ctaShimmer {
0%, 100% { background-position: 160% 0, 0 0; }
50% { background-position: -60% 0, 0 0; }
}
@keyframes ctaMetal {
0%, 100% { background-position: 100% 50%; }
50% { background-position: 0 50%; }
}
.hero-content > * {
opacity: 0;
animation: fadeUp 0.6s ease-out forwards;
}
.hero-content > *:nth-child(2) { animation-delay: 0.1s; }
.hero-content > *:nth-child(3) { animation-delay: 0.2s; }
.hero-content > *:nth-child(4) { animation-delay: 0.3s; }
.hero-content > *:nth-child(5) { animation-delay: 0.4s; }
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.hero-content > *,
.demo-cta::before,
.demo-cta span,
.demo-cta::after {
animation: none;
}
}
</style>
</head>
<body>
<!-- Navbar -->
<nav class="navbar">
<div class="container">
<a href="#" class="nav-brand">
<img src="fhirflame_logo.svg" alt="FhirFlame">
</a>
<button class="nav-toggle" onclick="document.querySelector('.nav-links').classList.toggle('open')" aria-label="Menu">&#9776;</button>
<ul class="nav-links">
<li><a href="#demo">Demo</a></li>
<li><a href="#capabilities">Platform</a></li>
<li><a href="#usecases">Use Cases</a></li>
<li><a href="https://github.com/leksval/fhirflame">GitHub</a></li>
<li><a href="https://huggingface.co/spaces/grasant/fhirflame" class="nav-cta">Live Demo</a></li>
</ul>
</div>
</nav>
<!-- Disclaimer -->
<div class="disclaimer">
<strong>Prototype / MVP</strong> - For development and testing with synthetic data only.
</div>
<!-- Hero -->
<section class="hero">
<div class="container">
<div class="hero-content">
<img src="fhirflame_logo.svg" alt="FhirFlame Logo" class="logo">
<h1>AI-Powered Medical Data Processing,<br><span>FHIR-Compliant by Design</span></h1>
<p class="hero-subtitle">
Ingest clinical documents, extract structured medical entities, and generate
validated FHIR R4/R5 bundles - with intelligent multi-provider AI routing
and built-in agent interoperability.
</p>
<div class="trust-badges">
<span class="trust-badge"><span class="dot dot--red"></span>FHIR R4 / R5</span>
<span class="trust-badge"><span class="dot dot--blue"></span>MCP Compatible</span>
<span class="trust-badge"><span class="dot dot--green"></span>Apache 2.0</span>
</div>
<div class="hero-actions">
<a href="https://huggingface.co/spaces/grasant/fhirflame" class="btn btn-primary demo-cta" target="_blank" rel="noopener"><span>Try&nbsp;&nbsp;&nbsp;Live Demo</span></a>
</div>
<p class="demo-requirement">
A free <a href="https://huggingface.co/join" target="_blank" rel="noopener">Hugging Face account</a>
is required. Sign in before opening the demo; a sleeping Space may take 2–3 minutes to start.
</p>
</div>
</div>
</section>
<!-- Metrics -->
<section class="metrics">
<div class="container">
<div class="metrics-grid">
<div class="metric">
<div class="metric-value">2.3s</div>
<div class="metric-label">Avg. processing time<br>per clinical document</div>
</div>
<div class="metric">
<div class="metric-value">100%</div>
<div class="metric-label">FHIR R4/R5<br>validation compliance</div>
</div>
<div class="metric">
<div class="metric-value">4</div>
<div class="metric-label">AI providers with<br>automatic fallback</div>
</div>
<div class="metric">
<div class="metric-value">29</div>
<div class="metric-label">Test modules covering<br>unit, integration, MCP</div>
</div>
<div class="metric">
<div class="metric-value">6</div>
<div class="metric-label">Docker-orchestrated<br>microservices</div>
</div>
<div class="metric">
<div class="metric-value">$0</div>
<div class="metric-label">Local dev cost<br>Ollama, no API keys</div>
</div>
</div>
</div>
</section>
<!-- Demo Video -->
<section class="demo-video" id="demo">
<div class="container">
<div class="section-header">
<div class="section-label">See It in Action</div>
<h2 class="section-title">Platform Demo</h2>
<p class="section-desc">Watch FhirFlame process a clinical document end-to-end: from raw text ingestion through AI entity extraction to a validated FHIR R4 bundle.</p>
</div>
<div class="video-wrapper" id="demoVideoWrapper">
<video id="demoVideo" preload="metadata" poster="" playsinline onclick="toggleDemo()">
<source src="r1_full.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<div class="video-overlay" id="videoOverlay" onclick="toggleDemo()">
<div class="play-btn">
<svg viewBox="0 0 24 24"><polygon points="8,5 19,12 8,19"/></svg>
</div>
</div>
</div>
</div>
</section>
<!-- Live Demo Experience -->
<section class="section section--alt" id="live-demo">
<div class="container">
<div class="section-header">
<div class="section-label">Explore the Hosted App</div>
<h2 class="section-title">What You Can Try in the Live Demo</h2>
<p class="section-desc">Use the six-tab Gradio experience to test FhirFlame's core medical-data workflows, inspect structured results, and follow processing activity in real time.</p>
</div>
<div class="cap-grid">
<div class="cap-card">
<div class="cap-icon cap-icon--blue">TXT</div>
<h3>Clinical Text Processing</h3>
<p>Paste a clinical note, extract structured entities, and optionally generate a FHIR bundle.</p>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--red">DOC</div>
<h3>Document Upload</h3>
<p>Process PDF, Word, text, and image files with OCR, entity extraction, and optional FHIR generation.</p>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--green">DCM</div>
<h3>DICOM Processing</h3>
<p>Upload DICOM imaging files to inspect metadata and create a FHIR ImagingStudy representation.</p>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--blue">SCL</div>
<h3>Scaling Visualization</h3>
<p>Explore a simulated Modal container auto-scaling workload with container and throughput metrics.</p>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--red">BAT</div>
<h3>Batch Processing</h3>
<p>Run 5–50 sample clinical notes, lab reports, or discharge summaries with live progress updates.</p>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--green">MON</div>
<h3>System Dashboard</h3>
<p>Review provider status, processing metrics, recent jobs, success rates, and system activity.</p>
</div>
</div>
<div class="hero-actions">
<a href="https://huggingface.co/spaces/grasant/fhirflame" class="btn btn-primary demo-cta" target="_blank" rel="noopener"><span>Try&nbsp;&nbsp;&nbsp;Live Demo</span></a>
</div>
<p class="demo-requirement">
FHIR generation is optional. Cloud-backed features depend on provider availability and configured credentials; local fallbacks are used where supported.
</p>
</div>
</section>
<!-- Why FhirFlame -->
<section class="section" id="why">
<div class="container">
<div class="section-header">
<div class="section-label">The Problem</div>
<h2 class="section-title">Why FhirFlame Exists</h2>
<p class="section-desc">Healthcare data is locked in unstructured formats. Converting it to interoperable standards manually is slow, expensive, and error-prone.</p>
</div>
<div class="why-grid">
<div class="why-card">
<div class="why-num cap-icon--red" style="color:var(--accent)">1</div>
<div>
<h3>Unstructured Medical Data Everywhere</h3>
<p>Clinical notes, lab reports, discharge summaries, and imaging reports arrive as free text, scanned PDFs, and proprietary formats. EHR systems need structured, coded data to be useful.</p>
<span class="arrow-label">FhirFlame auto-extracts entities and structures them into FHIR bundles</span>
</div>
</div>
<div class="why-card">
<div class="why-num cap-icon--blue" style="color:var(--trust)">2</div>
<div>
<h3>FHIR Conversion Is Hard to Get Right</h3>
<p>Building a compliant FHIR bundle by hand requires deep HL7 expertise. One missing field or wrong reference breaks downstream systems. Validation is tedious and easy to get wrong.</p>
<span class="arrow-label">100% schema-validated output, zero dummy data, every field traced to source</span>
</div>
</div>
<div class="why-card">
<div class="why-num cap-icon--green" style="color:var(--success)">3</div>
<div>
<h3>No Affordable AI Tooling for Small Teams</h3>
<p>Cloud AI APIs cost money per call. Many healthcare teams can't justify API spend for development and testing. Existing tools require expensive enterprise licenses.</p>
<span class="arrow-label">Run entirely local with Ollama at $0 cost, scale to cloud only when needed</span>
</div>
</div>
<div class="why-card">
<div class="why-num cap-icon--blue" style="color:var(--trust)">4</div>
<div>
<h3>AI Agents Can't Access Healthcare Tools</h3>
<p>LLM-based agents (Claude, GPT, custom) lack purpose-built medical tools. There's no standard way for an AI agent to process a clinical document and get back structured FHIR data.</p>
<span class="arrow-label">MCP server gives any agent instant access to medical processing</span>
</div>
</div>
</div>
</div>
</section>
<!-- Capabilities -->
<section class="section section--alt" id="capabilities">
<div class="container">
<div class="section-header">
<div class="section-label">Core Capabilities</div>
<h2 class="section-title">Built for Healthcare Workflows</h2>
<p class="section-desc">From document ingestion to FHIR-compliant output, every component is designed for medical data processing at scale.</p>
</div>
<div class="cap-grid">
<div class="cap-card">
<div class="cap-icon cap-icon--red">R4</div>
<h3>FHIR Validation Engine</h3>
<p>Generate and validate HL7 FHIR R4/R5 bundles with 100% compliance scoring. Seamless EHR integration with structured, standards-conformant output.</p>
<ul class="cap-list">
<li>Zero-dummy-data policy</li>
<li>Healthcare-professional validated</li>
<li>HL7 schema conformance</li>
</ul>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--blue">AI</div>
<h3>Multi-Provider AI Routing</h3>
<p>Intelligent cost-aware routing across Ollama (local/free), Modal Labs L4 GPU, HuggingFace inference, and Mistral Vision with automatic fallback.</p>
<ul class="cap-list">
<li>Free local development</li>
<li>Serverless GPU auto-scaling</li>
<li>Provider health monitoring</li>
</ul>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--green">MCP</div>
<h3>Agent Interoperability</h3>
<p>Built-in Model Context Protocol server with two healthcare-specific tools for seamless integration with Claude, GPT, and other LLM-based agents.</p>
<ul class="cap-list">
<li>process_medical_document()</li>
<li>validate_fhir_bundle()</li>
<li>Agent-to-agent REST API</li>
</ul>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--red">OCR</div>
<h3>Document Intelligence</h3>
<p>Mistral Vision OCR for medical document processing with high-accuracy entity extraction across clinical notes, lab reports, and radiology reports.</p>
<ul class="cap-list">
<li>PDF, DICOM, TXT, DOCX support</li>
<li>Condition &amp; medication extraction</li>
<li>Vitals and patient data parsing</li>
</ul>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--blue">DCM</div>
<h3>DICOM Processing</h3>
<p>Extract and process medical imaging metadata via pydicom. Map DICOM data to FHIR ImagingStudy resources for radiology and diagnostic workflows.</p>
<ul class="cap-list">
<li>DICOM metadata extraction</li>
<li>ImagingStudy resource mapping</li>
<li>Standard imaging format support</li>
</ul>
</div>
<div class="cap-card">
<div class="cap-icon cap-icon--green">MON</div>
<h3>Observability &amp; Audit</h3>
<p>Langfuse-powered tracing and monitoring with PostgreSQL persistence, ClickHouse analytics, and comprehensive audit trails for compliance.</p>
<ul class="cap-list">
<li>Real-time performance dashboard</li>
<li>Complete audit trail logging</li>
<li>Healthcare compliance tracking</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Feature Deep-Dive: MCP Agent Integration -->
<section class="features-detail" id="features-detail">
<div class="container">
<div class="fd-grid">
<div class="fd-content">
<span class="fd-label fd-label--green">MCP + A2A Protocol</span>
<h3 class="fd-title">First-Class Agent Interoperability</h3>
<p class="fd-desc">FhirFlame implements the Model Context Protocol for programmatic access from Claude, GPT, and custom agents. Its A2A REST API connects EHRs, labs, and other services.</p>
<div class="fd-highlights">
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--green">&#x2713;</div>
<span><strong>process_medical_document():</strong> send clinical text and receive structured entities with a validated FHIR bundle in a single call</span>
</div>
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--green">&#x2713;</div>
<span><strong>validate_fhir_bundle():</strong> submit any FHIR bundle for R4/R5 compliance scoring and detailed error reporting</span>
</div>
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--green">&#x2713;</div>
<span><strong>Agent-to-Agent REST API:</strong> FastAPI endpoints on port 8000 for synchronous and async document processing, health checks, and job tracking</span>
</div>
</div>
</div>
<div class="fd-visual">
<div class="fd-visual-label">MCP Tool Call Example</div>
<pre>{
"tool": "process_medical_document",
"input": {
"document_content": "Patient presents with
acute chest pain, BP 142/91,
HR 98. History of hypertension.
Started on Metoprolol 50mg.",
"document_type": "clinical_note",
"extract_entities": true,
"generate_fhir": true
}
}</pre>
<div class="fd-stat-row">
<div class="fd-stat">
<div class="fd-stat-value">2</div>
<div class="fd-stat-label">MCP Tools</div>
</div>
<div class="fd-stat">
<div class="fd-stat-value">REST</div>
<div class="fd-stat-label">A2A Protocol</div>
</div>
<div class="fd-stat">
<div class="fd-stat-value">Async</div>
<div class="fd-stat-label">Job Queue</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Feature Deep-Dive: Multi-Provider AI -->
<section class="features-detail section--alt">
<div class="container">
<div class="fd-grid fd-grid--reverse">
<div class="fd-content">
<span class="fd-label fd-label--blue">Intelligent Routing</span>
<h3 class="fd-title">Cost-Aware Multi-Provider AI</h3>
<p class="fd-desc">The routing engine selects the optimal AI provider for each request based on cost, latency, and availability. Start free with local Ollama, then seamlessly scale to GPU cloud when you need production throughput. If a provider goes down, the system automatically falls back.</p>
<div class="fd-highlights">
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--blue">1</div>
<span><strong>Ollama (Local):</strong> CodeLlama 13B runs on your machine at zero cost with local processing and no API key.</span>
</div>
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--blue">2</div>
<span><strong>Modal Labs (L4 GPU):</strong> serverless GPU scaling for production. It provisions NVIDIA L4 instances and scales to zero when idle.</span>
</div>
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--blue">3</div>
<span><strong>HuggingFace + Mistral:</strong> medical-domain models (BioBERT, ClinicalBERT) and multimodal vision OCR for scanned documents.</span>
</div>
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--blue">&#x21BB;</div>
<span><strong>Automatic Fallback:</strong> the router selects the next available provider when a service is slow or unavailable.</span>
</div>
</div>
</div>
<div class="fd-visual">
<div class="fd-visual-label">Provider Priority Chain</div>
<pre>Router Decision Engine
├─ Priority 1: Ollama (local)
│ ├─ Cost: $0
│ ├─ Latency: ~2.3s
│ └─ Status: ● healthy
├─ Priority 2: Modal Labs (GPU)
│ ├─ Cost: usage-based
│ ├─ Latency: ~1.1s
│ └─ Status: ● standby
├─ Priority 3: HuggingFace
│ ├─ Cost: free tier / paid
│ ├─ Latency: ~3.0s
│ └─ Status: ● healthy
└─ Priority 4: Mistral Vision
├─ Cost: usage-based
├─ Latency: ~2.8s (OCR)
└─ Status: ● healthy</pre>
<div class="fd-stat-row">
<div class="fd-stat">
<div class="fd-stat-value">4</div>
<div class="fd-stat-label">Providers</div>
</div>
<div class="fd-stat">
<div class="fd-stat-value">$0</div>
<div class="fd-stat-label">Local Cost</div>
</div>
<div class="fd-stat">
<div class="fd-stat-value">Auto</div>
<div class="fd-stat-label">Fallback</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Feature Deep-Dive: FHIR Compliance -->
<section class="features-detail">
<div class="container">
<div class="fd-grid">
<div class="fd-content">
<span class="fd-label fd-label--red">Healthcare Standards</span>
<h3 class="fd-title">100% FHIR R4/R5 Compliance</h3>
<p class="fd-desc">Every output bundle is validated against official HL7 FHIR schemas. A zero-dummy-data policy requires each resource field to map directly to extracted clinical entities. Bundles are ready for EHR integration.</p>
<div class="fd-highlights">
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--red">R4</div>
<span><strong>FHIR R4 + R5 Dual Support:</strong> generate bundles for either specification version, configurable per request or globally</span>
</div>
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--red">&#x2713;</div>
<span><strong>Entity-to-Resource Mapping:</strong> conditions, medications, vitals, and patient demographics map to Patient, Condition, MedicationStatement, and Observation resources</span>
</div>
<div class="fd-highlight">
<div class="fd-highlight-icon fd-highlight-icon--red">&#x2713;</div>
<span><strong>Healthcare-Professional Validated:</strong> clinical domain experts review output quality for semantic correctness</span>
</div>
</div>
</div>
<div class="fd-visual">
<div class="fd-visual-label">Validated FHIR Bundle Output</div>
<pre>{
"resourceType": "Bundle",
"type": "collection",
"entry": [
{
"resource": {
"resourceType": "Patient",
"name": [{"given": ["John"]}],
"birthDate": "1965-03-15"
}
},
{
"resource": {
"resourceType": "Condition",
"code": {
"text": "Hypertension"
},
"clinicalStatus": "active"
}
}
]
}</pre>
<div class="fd-stat-row">
<div class="fd-stat">
<div class="fd-stat-value">100%</div>
<div class="fd-stat-label">Compliance</div>
</div>
<div class="fd-stat">
<div class="fd-stat-value">R4/R5</div>
<div class="fd-stat-label">Dual Version</div>
</div>
<div class="fd-stat">
<div class="fd-stat-value">0</div>
<div class="fd-stat-label">Dummy Data</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Pipeline -->
<section class="section section--alt" id="pipeline">
<div class="container">
<div class="section-header">
<div class="section-label">Processing Pipeline</div>
<h2 class="section-title">From Document to FHIR Bundle</h2>
<p class="section-desc">A multi-stage pipeline that transforms unstructured medical documents into validated, standards-compliant healthcare data.</p>
</div>
<div class="pipeline-track">
<div class="pipeline-step">
<div class="pipeline-num">1</div>
<h4>Document Ingestion</h4>
<p class="pipeline-detail">PDF, DICOM, clinical text, and lab reports are ingested and pre-processed with OCR via Mistral Vision and text extraction via pydicom and PyMuPDF.</p>
</div>
<div class="pipeline-step">
<div class="pipeline-num">2</div>
<h4>MCP Agent Routing</h4>
<p class="pipeline-detail">The MCP server selects the appropriate tool, routes to the optimal AI provider based on cost and availability, and tracks job state in PostgreSQL.</p>
</div>
<div class="pipeline-step">
<div class="pipeline-num">3</div>
<h4>AI Entity Extraction</h4>
<p class="pipeline-detail">Medical NLP models extract conditions, medications, vitals, and patient information. Scaling flows automatically from local Ollama to Modal L4 GPU.</p>
</div>
<div class="pipeline-step">
<div class="pipeline-num">4</div>
<h4>FHIR Compliance</h4>
<p class="pipeline-detail">Extracted entities are mapped to HL7 FHIR R4/R5 schemas, validated for 100% compliance, and output as EHR-ready structured bundles.</p>
</div>
</div>
</div>
</section>
<!-- Use Cases -->
<section class="section" id="usecases">
<div class="container">
<div class="section-header">
<div class="section-label">Who It's For</div>
<h2 class="section-title">Real-World Use Cases</h2>
<p class="section-desc">FhirFlame is built for anyone who needs to turn medical text into structured, standards-compliant healthcare data.</p>
</div>
<div class="uc-grid">
<div class="uc-card">
<div class="uc-header">
<div class="uc-icon cap-icon--red">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
</div>
<h3>Hospital &amp; Clinic IT</h3>
</div>
<p>Automate the conversion of clinical notes, discharge summaries, and lab reports into FHIR bundles for EHR ingestion. Reduce manual data entry and transcription errors.</p>
<div class="uc-flow">
<span class="uc-flow-step">Clinical Note</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">AI Extraction</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">FHIR Bundle</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">EHR System</span>
</div>
</div>
<div class="uc-card">
<div class="uc-header">
<div class="uc-icon cap-icon--blue">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
</div>
<h3>Health Tech Startups</h3>
</div>
<p>Use the A2A API to add FHIR-compliant document processing and ship interoperable features faster.</p>
<div class="uc-flow">
<span class="uc-flow-step">Your App</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">A2A REST API</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">FHIR Output</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">Your Users</span>
</div>
</div>
<div class="uc-card">
<div class="uc-header">
<div class="uc-icon cap-icon--green">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
</div>
<h3>AI Agent Developers</h3>
</div>
<p>Give your Claude, GPT, or custom LLM agent healthcare capabilities instantly. The MCP server exposes two tools that turn any agent into a medical document processor.</p>
<div class="uc-flow">
<span class="uc-flow-step">LLM Agent</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">MCP Call</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">Entities + FHIR</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">Agent Response</span>
</div>
</div>
<div class="uc-card">
<div class="uc-header">
<div class="uc-icon cap-icon--red">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>
</div>
<h3>Research &amp; Education</h3>
</div>
<p>Process medical datasets for research analysis. Use as a teaching tool for FHIR standards, medical NLP, and healthcare interoperability concepts. Runs locally for full data privacy.</p>
<div class="uc-flow">
<span class="uc-flow-step">Medical Dataset</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">Batch Processing</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">Structured Data</span>
<span class="uc-flow-arrow">&rarr;</span>
<span class="uc-flow-step">Analysis</span>
</div>
</div>
</div>
</div>
</section>
<!-- Supported Formats -->
<section class="section section--alt" id="formats">
<div class="container">
<div class="section-header">
<div class="section-label">Input &amp; Output</div>
<h2 class="section-title">What Goes In, What Comes Out</h2>
<p class="section-desc">FhirFlame accepts diverse medical document formats and produces standards-compliant structured output.</p>
</div>
<div class="fmt-container">
<div class="fmt-box">
<h3>Input Formats</h3>
<ul class="fmt-list">
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--red">TXT</div>
<div><div class="fmt-item-text">Clinical Notes</div><div class="fmt-item-sub">Free-text patient encounters, assessments</div></div>
</li>
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--blue">PDF</div>
<div><div class="fmt-item-text">PDF Documents</div><div class="fmt-item-sub">Scanned reports, lab results via OCR</div></div>
</li>
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--green">DCM</div>
<div><div class="fmt-item-text">DICOM Files</div><div class="fmt-item-sub">Medical imaging metadata extraction</div></div>
</li>
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--blue">DOC</div>
<div><div class="fmt-item-text">DOCX Files</div><div class="fmt-item-sub">Word documents, discharge summaries</div></div>
</li>
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--red">IMG</div>
<div><div class="fmt-item-text">Images</div><div class="fmt-item-sub">Scanned documents via Mistral Vision OCR</div></div>
</li>
</ul>
</div>
<div class="fmt-arrow">
<div class="fmt-arrow-label">FhirFlame AI</div>
<div class="fmt-arrow-line"></div>
<div style="font-size:0.72rem;color:var(--text-muted);text-align:center;line-height:1.4">Entity<br>Extraction<br>&amp; Validation</div>
</div>
<div class="fmt-box">
<h3>Output</h3>
<ul class="fmt-list">
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--green">R4</div>
<div><div class="fmt-item-text">FHIR R4 Bundles</div><div class="fmt-item-sub">HL7 FHIR R4 JSON, EHR-ready</div></div>
</li>
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--green">R5</div>
<div><div class="fmt-item-text">FHIR R5 Bundles</div><div class="fmt-item-sub">Latest FHIR specification support</div></div>
</li>
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--blue">ENT</div>
<div><div class="fmt-item-text">Extracted Entities</div><div class="fmt-item-sub">Conditions, medications, vitals, patient info</div></div>
</li>
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--red">RPT</div>
<div><div class="fmt-item-text">Compliance Report</div><div class="fmt-item-sub">Validation score, errors, field coverage</div></div>
</li>
<li class="fmt-item">
<div class="fmt-item-icon cap-icon--blue">LOG</div>
<div><div class="fmt-item-text">Audit Trail</div><div class="fmt-item-sub">Full trace via Langfuse for every job</div></div>
</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Architecture -->
<section class="section" id="architecture">
<div class="container">
<div class="section-header">
<div class="section-label">System Design</div>
<h2 class="section-title">Microservices Architecture</h2>
<p class="section-desc">Container-orchestrated services connected via Docker Compose for reproducible, healthcare-grade deployments.</p>
</div>
<div class="arch-grid">
<div class="arch-node">
<div class="arch-node-label">Frontend</div>
<div class="arch-node-tech">Gradio Web UI</div>
<span class="arch-node-port">Port 7860</span>
</div>
<div class="arch-node">
<div class="arch-node-label">API Gateway</div>
<div class="arch-node-tech">FastAPI + MCP Server</div>
<span class="arch-node-port">Port 8000</span>
</div>
<div class="arch-node">
<div class="arch-node-label">AI Processing</div>
<div class="arch-node-tech">Ollama + Modal Scaling</div>
<span class="arch-node-port">Port 11434</span>
</div>
<div class="arch-node">
<div class="arch-node-label">Data Layer</div>
<div class="arch-node-tech">PostgreSQL + ClickHouse</div>
<span class="arch-node-port">Persistent Storage</span>
</div>
<div class="arch-node">
<div class="arch-node-label">Observability</div>
<div class="arch-node-tech">Langfuse Analytics</div>
<span class="arch-node-port">Port 3000</span>
</div>
<div class="arch-node">
<div class="arch-node-label">FHIR Engine</div>
<div class="arch-node-tech">R4/R5 Validation</div>
<span class="arch-node-port">Healthcare Standards</span>
</div>
</div>
</div>
</section>
<!-- Quick Start -->
<section class="section section--alt" id="quickstart">
<div class="container">
<div class="section-header">
<div class="section-label">Getting Started</div>
<h2 class="section-title">Deploy in Minutes</h2>
<p class="section-desc">Run the full stack with Docker or start lightweight with a local Python environment.</p>
</div>
<div class="qs-grid">
<div class="qs-card">
<h3>Docker (Recommended)</h3>
<div class="qs-label">Full stack - single command</div>
<pre>git clone https://github.com/leksval/fhirflame.git
cd fhirflame
cp .env.example .env
docker compose -f docker-compose.local.yml up -d</pre>
<table class="qs-ports">
<tr><td>Gradio UI</td><td>localhost:7860</td></tr>
<tr><td>A2A API</td><td>localhost:8000</td></tr>
<tr><td>Langfuse</td><td>localhost:3000</td></tr>
<tr><td>Ollama</td><td>localhost:11434</td></tr>
</table>
</div>
<div class="qs-card">
<h3>Local Python</h3>
<div class="qs-label">Lightweight - Gradio UI only</div>
<pre>git clone https://github.com/leksval/fhirflame.git
cd fhirflame
python -m venv .venv &amp;&amp; source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
python app.py</pre>
<p class="qs-note">
On Windows use <code>.venv\Scripts\activate</code> instead.
No API keys required - Ollama runs locally at zero cost.
</p>
</div>
</div>
</div>
</section>
<!-- AI Providers -->
<section class="section" id="providers">
<div class="container">
<div class="section-header">
<div class="section-label">AI Infrastructure</div>
<h2 class="section-title">Multi-Provider Configuration</h2>
<p class="section-desc">Configure providers via environment variables. Start free with Ollama and add cloud providers as needed.</p>
</div>
<div class="prov-grid">
<div class="prov-card">
<h4>Ollama (Local)</h4>
<p>No API keys required. Run CodeLlama 13B Instruct locally for development and testing.</p>
<p><code>USE_REAL_OLLAMA=true</code></p>
<span class="prov-tag prov-tag--free">Free</span>
</div>
<div class="prov-card">
<h4>HuggingFace</h4>
<p>Medical domain models (BioBERT, ClinicalBERT) and HF Spaces hosting with enterprise inference endpoints.</p>
<p><code>HF_TOKEN</code></p>
<span class="prov-tag prov-tag--paid">Free tier available</span>
</div>
<div class="prov-card">
<h4>Modal Labs</h4>
<p>Serverless L4 GPU auto-scaling for production workloads with automatic provider fallback.</p>
<p><code>MODAL_TOKEN_ID</code></p>
<span class="prov-tag prov-tag--paid">Usage-based</span>
</div>
<div class="prov-card">
<h4>Mistral Vision</h4>
<p>Multimodal AI for medical document OCR and text extraction from imaging and scanned documents.</p>
<p><code>MISTRAL_API_KEY</code></p>
<span class="prov-tag prov-tag--paid">Usage-based</span>
</div>
<div class="prov-card">
<h4>Langfuse</h4>
<p>LLM observability and analytics with real-time job tracking, backed by PostgreSQL and ClickHouse.</p>
<p><code>LANGFUSE_SECRET_KEY</code></p>
<span class="prov-tag prov-tag--free">Self-hosted</span>
</div>
<div class="prov-card">
<h4>HF Spaces Hosting</h4>
<p>Deploy and host FhirFlame directly on HuggingFace Spaces with public or private access.</p>
<p><code>HF_TOKEN</code></p>
<span class="prov-tag prov-tag--free">Free tier available</span>
</div>
</div>
</div>
</section>
<!-- Security & Compliance -->
<section class="section section--alt" id="security">
<div class="container">
<div class="section-header">
<div class="section-label">Trust &amp; Compliance</div>
<h2 class="section-title">Healthcare Security</h2>
<p class="section-desc">Security patterns designed for healthcare environments with defense-in-depth principles.</p>
</div>
<div class="sec-grid">
<div class="sec-card">
<h3>Data Protection</h3>
<ul class="sec-list">
<li>Container isolation via Docker</li>
<li>Local processing for sensitive data</li>
<li>Encrypted environment configuration</li>
<li>Zero-dummy-data policy</li>
</ul>
</div>
<div class="sec-card">
<h3>Compliance Framework</h3>
<ul class="sec-list">
<li>HIPAA-aware architecture</li>
<li>Comprehensive audit trail logging</li>
<li>Healthcare data governance</li>
<li>Regulatory evaluation support</li>
</ul>
</div>
<div class="sec-card">
<h3>Authentication</h3>
<ul class="sec-list">
<li>JWT token-based authentication</li>
<li>OAuth 2.0 with PKCE flow</li>
<li>Role-based access control</li>
<li>Session management with expiry</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Tech Stack -->
<section class="section" id="stack">
<div class="container">
<div class="section-header">
<div class="section-label">Under the Hood</div>
<h2 class="section-title">Technology Stack</h2>
<p class="section-desc">Open-source technologies chosen for reliability, performance, and healthcare-grade standards.</p>
</div>
<div class="stack-grid">
<div class="stack-group">
<h4>Core Platform</h4>
<div class="stack-items">
<div class="stack-item"><span class="stack-dot" style="background:var(--trust)"></span> Python 3.11</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--trust)"></span> FastAPI + Uvicorn</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--trust)"></span> Gradio Web UI</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--trust)"></span> asyncio</div>
</div>
</div>
<div class="stack-group">
<h4>AI / Machine Learning</h4>
<div class="stack-items">
<div class="stack-item"><span class="stack-dot" style="background:var(--accent)"></span> Ollama (CodeLlama 13B)</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--accent)"></span> Modal Labs (L4 GPU)</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--accent)"></span> HuggingFace Inference</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--accent)"></span> Mistral Vision OCR</div>
</div>
</div>
<div class="stack-group">
<h4>Healthcare Standards</h4>
<div class="stack-items">
<div class="stack-item"><span class="stack-dot" style="background:var(--success)"></span> FHIR R4/R5 (fhir.resources)</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--success)"></span> DICOM (pydicom)</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--success)"></span> HL7 Standards</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--success)"></span> MCP / A2A Protocols</div>
</div>
</div>
<div class="stack-group">
<h4>Infrastructure</h4>
<div class="stack-items">
<div class="stack-item"><span class="stack-dot" style="background:var(--text-muted)"></span> Docker Compose</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--text-muted)"></span> PostgreSQL</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--text-muted)"></span> ClickHouse</div>
<div class="stack-item"><span class="stack-dot" style="background:var(--text-muted)"></span> Langfuse</div>
</div>
</div>
</div>
</div>
</section>
<!-- CTA -->
<section class="cta-section">
<div class="container">
<h2>Start Processing Medical Documents Today</h2>
<p>Try the hosted demo with a free Hugging Face account, or deploy locally in under 5 minutes with Docker.</p>
<div class="cta-actions">
<a href="https://huggingface.co/spaces/grasant/fhirflame" class="btn btn-primary demo-cta" target="_blank" rel="noopener"><span>Try&nbsp;&nbsp;&nbsp;Live Demo</span></a>
<a href="https://github.com/leksval/fhirflame" class="btn btn-outline">View on GitHub</a>
</div>
<p class="demo-requirement">Sign in to Hugging Face first. Allow 2–3 minutes for the L4 Space to wake after inactivity.</p>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="footer-grid">
<div class="footer-col">
<h4>Project</h4>
<ul>
<li><a href="https://github.com/leksval/fhirflame">GitHub Repository</a></li>
<li><a href="https://huggingface.co/spaces/grasant/fhirflame">Live Demo</a></li>
<li><a href="https://leksval.github.io/fhirflame/">Documentation</a></li>
<li><a href="https://github.com/leksval/fhirflame/blob/main/LICENSE">Apache 2.0 License</a></li>
</ul>
</div>
<div class="footer-col">
<h4>Documentation</h4>
<ul>
<li><a href="https://github.com/leksval/fhirflame#quick-start">Quick Start Guide</a></li>
<li><a href="https://github.com/leksval/fhirflame#mcp-tools">MCP Tools</a></li>
<li><a href="https://github.com/leksval/fhirflame#a2a-api">A2A API Reference</a></li>
<li><a href="https://github.com/leksval/fhirflame#configuration">Configuration</a></li>
</ul>
</div>
<div class="footer-col">
<h4>Standards</h4>
<ul>
<li><a href="https://www.hl7.org/fhir/">HL7 FHIR</a></li>
<li><a href="https://modelcontextprotocol.io/">Model Context Protocol</a></li>
<li><a href="https://www.dicomstandard.org/">DICOM Standard</a></li>
</ul>
</div>
</div>
<div class="footer-bottom">
<p><strong>Prototype / MVP</strong> - Technology demonstration for development and testing purposes only.</p>
<p>Apache License 2.0 - Open Source Healthcare AI Platform</p>
</div>
</div>
</footer>
<script>
function toggleDemo() {
var video = document.getElementById('demoVideo');
var overlay = document.getElementById('videoOverlay');
if (video.paused) {
video.playbackRate = 0.8;
video.play();
overlay.classList.add('hidden');
} else {
video.pause();
overlay.classList.remove('hidden');
}
}
document.getElementById('demoVideo').addEventListener('ended', function() {
document.getElementById('videoOverlay').classList.remove('hidden');
});
</script>
</body>
</html>