app / src /pages /Index.tsx
itsLu's picture
Upload 88 files
2586888 verified
import { useState } from "react";
import { Navigation } from "@/components/Navigation";
import { UploadZone } from "@/components/UploadZone";
import { ResultsDisplay } from "@/components/ResultsDisplay";
import { AboutPage } from "@/components/AboutPage";
import { Heart, Sparkles } from "lucide-react";
import { useToast } from "@/hooks/use-toast";
const Index = () => {
const [activeTab, setActiveTab] = useState<"upload" | "about">("upload");
const [isLoading, setIsLoading] = useState(false);
const [results, setResults] = useState<typeof mockResult | null>(null);
const { toast } = useToast();
const handleUpload = async (file: File) => {
setIsLoading(true);
setResults(null);
// Call backend API (served from the same Hugging Face Space)
try {
const formData = new FormData();
formData.append("video", file);
const response = await fetch("/api/analyze", {
method: "POST",
body: formData,
});
if (!response.ok) {
const msg = await response.text();
throw new Error(msg || "Analysis failed");
}
const data = await response.json();
setResults({
ejectionFraction: data.ejectionFraction,
heartFunction: data.heartFunction,
});
toast({
title: "Analysis Complete",
description: "Your echocardiography video has been analyzed successfully.",
});
} catch (error) {
toast({
title: "Analysis Failed",
description: "There was an error analyzing your video. Please try again.",
variant: "destructive",
});
} finally {
setIsLoading(false);
}
};
return (
<div className="min-h-screen" style={{ background: "var(--gradient-hero)" }}>
<Navigation activeTab={activeTab} setActiveTab={setActiveTab} />
<main className="container mx-auto px-4 py-8">
{activeTab === "upload" ? (
<div className="space-y-8">
{/* Hero Section */}
<div className="text-center animate-fade-in">
<div className="mb-4 inline-flex items-center gap-2 rounded-full border border-primary/20 bg-primary/5 px-4 py-1.5 text-sm text-primary">
<Sparkles className="h-4 w-4" />
AI-Powered Cardiac Analysis
</div>
<h1 className="mb-4 font-display text-4xl font-bold tracking-tight sm:text-5xl">
Analyze Your{" "}
<span className="gradient-text">Echocardiography</span>
</h1>
<p className="mx-auto max-w-2xl text-lg text-muted-foreground">
Upload your echocardiography video and let our AI model automatically
extract key cardiac measurements and assess heart function.
</p>
</div>
{/* Upload Zone */}
<UploadZone onUpload={handleUpload} isLoading={isLoading} />
{/* Results */}
{results && <ResultsDisplay results={results} />}
{/* Features */}
{!results && !isLoading && (
<div className="mx-auto max-w-2xl animate-fade-in" style={{ animationDelay: "200ms" }}>
<div className="grid gap-6 sm:grid-cols-2">
<div className="flex items-start gap-3 rounded-xl border border-border/50 bg-card/50 p-4">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
<Heart className="h-5 w-5 text-primary" />
</div>
<div>
<h3 className="font-medium">Ejection Fraction</h3>
<p className="text-sm text-muted-foreground">
Accurate EF calculation for cardiac assessment
</p>
</div>
</div>
<div className="flex items-start gap-3 rounded-xl border border-border/50 bg-card/50 p-4">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
<Heart className="h-5 w-5 text-primary" />
</div>
<div>
<h3 className="font-medium">Function Status</h3>
<p className="text-sm text-muted-foreground">
AI-based heart function classification
</p>
</div>
</div>
</div>
</div>
)}
</div>
) : (
<AboutPage />
)}
</main>
</div>
);
};
export default Index;