'use client'; import { motion } from 'framer-motion'; import { BrainCircuit, CheckCircle2, Circle, Loader2, Mic, UploadCloud, } from 'lucide-react'; import type { LucideIcon } from 'lucide-react'; import { useMemo } from 'react'; import { useAppStore } from '@/store/useAppStore'; import { Card } from '@/components/ui/Card'; import { Reveal } from '@/components/ui/Reveal'; import { SectionHeader } from '@/components/ui/SectionHeader'; import { cn } from '@/lib/utils'; type StepStatus = 'pending' | 'active' | 'complete' | 'error'; type PipelineStep = { id: string; label: string; description: string; icon: LucideIcon; }; const PIPELINE_STEPS: PipelineStep[] = [ { id: 'upload', label: 'Upload', description: 'Audio file sent to the API', icon: UploadCloud, }, { id: 'transcribe', label: 'Transcription', description: 'Whisper converts speech to text', icon: Mic, }, { id: 'extract', label: 'Feature Extraction', description: 'LLaMA analyzes transcript signals', icon: BrainCircuit, }, { id: 'ready', label: 'Pipeline Complete', description: 'Transcript and insights ready', icon: CheckCircle2, }, ]; function resolveStepStatuses(state: { audioFile: File | null; isUploading: boolean; uploadProgress: number; isExtracting: boolean; transcription: string; features: unknown; error: string | null; recordingState: string; }): Record { const { audioFile, isUploading, uploadProgress, isExtracting, transcription, features, error, recordingState, } = state; const statuses: Record = { upload: 'pending', transcribe: 'pending', extract: 'pending', ready: 'pending', }; if (error && audioFile) { if (isUploading || uploadProgress < 100) statuses.upload = 'error'; else if (!transcription) statuses.transcribe = 'error'; else statuses.extract = 'error'; return statuses; } const liveActive = recordingState === 'recording' || recordingState === 'processing' || recordingState === 'analyzing'; if (!audioFile && !liveActive && !transcription) { return statuses; } if (isUploading) { statuses.upload = uploadProgress < 60 ? 'active' : 'complete'; statuses.transcribe = uploadProgress >= 60 ? 'active' : 'pending'; return statuses; } if (isExtracting || recordingState === 'analyzing') { statuses.upload = 'complete'; statuses.transcribe = 'complete'; statuses.extract = 'active'; return statuses; } if (recordingState === 'recording' || recordingState === 'processing') { statuses.upload = 'active'; statuses.transcribe = recordingState === 'processing' ? 'active' : 'pending'; return statuses; } if (transcription && features) { statuses.upload = 'complete'; statuses.transcribe = 'complete'; statuses.extract = 'complete'; statuses.ready = 'complete'; return statuses; } if (transcription) { statuses.upload = 'complete'; statuses.transcribe = 'complete'; return statuses; } if (audioFile) { statuses.upload = 'complete'; statuses.transcribe = 'active'; } return statuses; } function StatusIcon({ status }: { status: StepStatus }) { if (status === 'active') { return ; } if (status === 'complete') { return ; } if (status === 'error') { return ; } return ; } export function ProcessingPipelineSection() { const audioFile = useAppStore((s) => s.audioFile); const isUploading = useAppStore((s) => s.isUploading); const uploadProgress = useAppStore((s) => s.uploadProgress); const isExtracting = useAppStore((s) => s.isExtracting); const transcription = useAppStore((s) => s.transcription); const features = useAppStore((s) => s.features); const error = useAppStore((s) => s.error); const recordingState = useAppStore((s) => s.recordingState); const stepStatuses = useMemo( () => resolveStepStatuses({ audioFile, isUploading, uploadProgress, isExtracting, transcription, features, error, recordingState, }), [audioFile, isUploading, uploadProgress, isExtracting, transcription, features, error, recordingState], ); const activeIndex = PIPELINE_STEPS.findIndex((step) => stepStatuses[step.id] === 'active'); const progress = activeIndex >= 0 ? ((activeIndex + 0.5) / PIPELINE_STEPS.length) * 100 : stepStatuses.ready === 'complete' ? 100 : 0; const statusLabel = useMemo(() => { if (error && audioFile) return 'Pipeline encountered an error'; if (stepStatuses.ready === 'complete') return 'All stages complete'; if (isExtracting || recordingState === 'analyzing') return 'Extracting features…'; if (isUploading) return 'Uploading and transcribing…'; if (recordingState === 'recording') return 'Recording live audio…'; if (recordingState === 'processing') return 'Processing recorded audio…'; if (!audioFile && !transcription) return 'Waiting for audio input'; return 'Pipeline idle'; }, [audioFile, error, isExtracting, isUploading, recordingState, stepStatuses.ready, transcription]); return (

{statusLabel}

{audioFile ? `${audioFile.name} · ${(audioFile.size / (1024 * 1024)).toFixed(2)} MB` : recordingState !== 'idle' ? 'Live recording session' : 'No active job'}

{(isUploading || isExtracting || recordingState !== 'idle') && ( In progress )}
    {PIPELINE_STEPS.map((step, index) => { const status = stepStatuses[step.id]; const Icon = step.icon; return (
  1. Step {index + 1}

    {step.label}

    {step.description}

  2. ); })}
{transcription && (

Latest output

{transcription}

)}
); }