emresar's picture
Upload folder using huggingface_hub
6678fa1 verified
import { useState, useEffect } from "react";
import { useAuth } from "@/_core/hooks/useAuth";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Music, Upload, Loader2, FileAudio, ArrowRight } from "lucide-react";
import { getLoginUrl, getAuthConfig, getHfLoginUrl, getDevLoginUrl, type AuthConfig } from "@/const";
import { trpc } from "@/lib/trpc";
import { useLocation } from "wouter";
export default function Home() {
const { user, loading, isAuthenticated } = useAuth();
const [, setLocation] = useLocation();
const tracks = trpc.tracks.list.useQuery(undefined, { enabled: isAuthenticated });
const [authConfig, setAuthConfig] = useState<AuthConfig | null>(null);
// Fetch auth config on mount
useEffect(() => {
getAuthConfig().then(setAuthConfig);
}, []);
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center">
<Loader2 className="w-8 h-8 animate-spin text-primary" />
</div>
);
}
if (!isAuthenticated) {
return (
<div className="min-h-screen bg-gradient-to-br from-purple-50 via-white to-blue-50">
<div className="container py-16">
<div className="max-w-4xl mx-auto">
<div className="text-center mb-12">
<div className="inline-flex items-center justify-center w-16 h-16 bg-primary/10 rounded-2xl mb-6">
<Music className="w-8 h-8 text-primary" />
</div>
<h1 className="text-5xl font-bold mb-4 bg-gradient-to-r from-purple-600 to-blue-600 bg-clip-text text-transparent">
AI Music Attribution System
</h1>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
Map AI-generated music stems to their original training sources using advanced audio fingerprinting and attribution methods
</p>
</div>
<div className="grid md:grid-cols-3 gap-6 mb-12">
<Card>
<CardHeader>
<div className="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center mb-3">
<FileAudio className="w-6 h-6 text-purple-600" />
</div>
<CardTitle className="text-lg">Stem Separation</CardTitle>
<CardDescription>
Automatically separate audio into vocals, drums, bass, and other instruments using Demucs
</CardDescription>
</CardHeader>
</Card>
<Card>
<CardHeader>
<div className="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-3">
<Music className="w-6 h-6 text-blue-600" />
</div>
<CardTitle className="text-lg">Audio Fingerprinting</CardTitle>
<CardDescription>
Generate unique fingerprints for each stem using Chromaprint technology
</CardDescription>
</CardHeader>
</Card>
<Card>
<CardHeader>
<div className="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center mb-3">
<ArrowRight className="w-6 h-6 text-green-600" />
</div>
<CardTitle className="text-lg">Source Attribution</CardTitle>
<CardDescription>
Match stems to training tracks using CLAP embeddings and FAISS similarity search
</CardDescription>
</CardHeader>
</Card>
</div>
<div className="text-center">
{/* Standard OAuth configured */}
{getLoginUrl() !== "#oauth-not-configured" && (
<>
<Button size="lg" asChild>
<a href={getLoginUrl()}>
Get Started
<ArrowRight className="ml-2 w-4 h-4" />
</a>
</Button>
<p className="text-sm text-muted-foreground mt-4">
Sign in to upload and analyze your AI-generated music
</p>
</>
)}
{/* No standard OAuth - show login options based on config */}
{getLoginUrl() === "#oauth-not-configured" && (
<>
{/* HuggingFace OAuth (for HF Spaces) */}
{authConfig?.hfOAuthEnabled && (
<>
<Button size="lg" asChild>
<a href={getHfLoginUrl()}>
Sign in with HuggingFace
<ArrowRight className="ml-2 w-4 h-4" />
</a>
</Button>
<p className="text-sm text-muted-foreground mt-4">
Sign in with your HuggingFace account to continue
</p>
</>
)}
{/* Dev/Demo login - show as fallback */}
{!authConfig?.hfOAuthEnabled && (
<>
<Button size="lg" asChild>
<a href={getDevLoginUrl()}>
Enter Demo
<ArrowRight className="ml-2 w-4 h-4" />
</a>
</Button>
<p className="text-sm text-muted-foreground mt-4">
{authConfig === null ? "Loading..." : "Click to access the demo"}
</p>
</>
)}
</>
)}
</div>
</div>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gradient-to-br from-purple-50 via-white to-blue-50">
<div className="container py-8">
<div className="max-w-6xl mx-auto">
<div className="flex items-center justify-between mb-8">
<div>
<h1 className="text-3xl font-bold mb-2">My Tracks</h1>
<p className="text-muted-foreground">
Upload AI-generated music to analyze its training data sources
</p>
</div>
<Button onClick={() => setLocation("/upload")}>
<Upload className="mr-2 w-4 h-4" />
Upload Track
</Button>
</div>
{tracks.isLoading ? (
<div className="flex items-center justify-center py-12">
<Loader2 className="w-8 h-8 animate-spin text-primary" />
</div>
) : tracks.data && tracks.data.length > 0 ? (
<div className="grid gap-4">
{tracks.data.map((track) => (
<Card
key={track.id}
className="hover:shadow-md transition-shadow cursor-pointer"
onClick={() => setLocation(`/track/${track.id}`)}
>
<CardHeader>
<div className="flex items-start justify-between">
<div className="flex-1">
<CardTitle className="text-xl mb-1">{track.title}</CardTitle>
{track.artist && (
<CardDescription className="text-base">{track.artist}</CardDescription>
)}
</div>
<div className="flex items-center gap-2">
{track.status === "pending" && (
<span className="text-sm text-yellow-600 bg-yellow-50 px-3 py-1 rounded-full">
Pending
</span>
)}
{track.status === "processing" && (
<span className="text-sm text-blue-600 bg-blue-50 px-3 py-1 rounded-full flex items-center gap-1">
<Loader2 className="w-3 h-3 animate-spin" />
Processing
</span>
)}
{track.status === "completed" && (
<span className="text-sm text-green-600 bg-green-50 px-3 py-1 rounded-full">
Completed
</span>
)}
{track.status === "failed" && (
<span className="text-sm text-red-600 bg-red-50 px-3 py-1 rounded-full">
Failed
</span>
)}
</div>
</div>
<div className="text-sm text-muted-foreground mt-2">
Uploaded {new Date(track.createdAt).toLocaleDateString()}
</div>
</CardHeader>
</Card>
))}
</div>
) : (
<Card>
<CardContent className="py-12 text-center">
<Music className="w-12 h-12 text-muted-foreground mx-auto mb-4" />
<h3 className="text-lg font-semibold mb-2">No tracks yet</h3>
<p className="text-muted-foreground mb-6">
Upload your first AI-generated track to get started
</p>
<Button onClick={() => setLocation("/upload")}>
<Upload className="mr-2 w-4 h-4" />
Upload Track
</Button>
</CardContent>
</Card>
)}
</div>
</div>
</div>
);
}