diff --git a/surfsense_web/components/tool-ui/audio.tsx b/surfsense_web/components/tool-ui/audio.tsx index acf6054fb..3dcaa5e66 100644 --- a/surfsense_web/components/tool-ui/audio.tsx +++ b/surfsense_web/components/tool-ui/audio.tsx @@ -1,7 +1,6 @@ "use client"; import { DownloadIcon, PauseIcon, PlayIcon, Volume2Icon, VolumeXIcon } from "lucide-react"; -import Image from "next/image"; import { useCallback, useEffect, useRef, useState } from "react"; import { Button } from "@/components/ui/button"; import { Slider } from "@/components/ui/slider"; @@ -12,8 +11,6 @@ interface AudioProps { assetId?: string; src: string; title: string; - description?: string; - artwork?: string; durationMs?: number; className?: string; } @@ -25,7 +22,7 @@ function formatTime(seconds: number): string { return `${mins}:${secs.toString().padStart(2, "0")}`; } -export function Audio({ id, src, title, description, artwork, durationMs, className }: AudioProps) { +export function Audio({ id, src, title, durationMs, className }: AudioProps) { const audioRef = useRef(null); const [isPlaying, setIsPlaying] = useState(false); const [currentTime, setCurrentTime] = useState(0); @@ -149,16 +146,17 @@ export function Audio({ id, src, title, description, artwork, durationMs, classN return (
-
- +
+

Audio Error

-
-

{title}

-

{error}

+
+
+

{title}

+

{error}

); @@ -168,121 +166,93 @@ export function Audio({ id, src, title, description, artwork, durationMs, classN
- {/* Hidden audio element */} -
- {/* Artwork */} -
-
- {artwork ? ( - {title} - ) : ( -
- -
- )} -
-
- - {/* Content */} -
- {/* Title and description */} -
-

{title}

- {description && ( -

- {description} -

- )} -
- - {/* Progress bar */} -
- -
- {formatTime(currentTime)} - {formatTime(duration)} -
-
-
+
+

{title}

- {/* Controls */} -
-
- {/* Play/Pause button */} - +
- {/* Volume control */} -
- - {/* Custom volume bar - visually distinct from progress slider */} -
-
-
-
- handleVolumeChange([Number.parseFloat(e.target.value)])} - className="absolute inset-0 h-full w-full cursor-pointer opacity-0" - aria-label="Volume" - /> -
+
+
+ +
+ {formatTime(currentTime)} + {formatTime(duration)}
- {/* Download button */} - +
+
+ + +
+ +
+
+
+
+ handleVolumeChange([Number.parseFloat(e.target.value)])} + className="absolute inset-0 h-full w-full cursor-pointer opacity-0" + aria-label="Volume" + /> +
+
+
+ + +
); diff --git a/surfsense_web/components/tool-ui/generate-podcast.tsx b/surfsense_web/components/tool-ui/generate-podcast.tsx index 9d6d47588..bac5b3d5c 100644 --- a/surfsense_web/components/tool-ui/generate-podcast.tsx +++ b/surfsense_web/components/tool-ui/generate-podcast.tsx @@ -1,12 +1,17 @@ "use client"; import { makeAssistantToolUI } from "@assistant-ui/react"; -import { AlertCircleIcon, MicIcon } from "lucide-react"; import { useParams, usePathname } from "next/navigation"; import { useCallback, useEffect, useRef, useState } from "react"; import { z } from "zod"; +import { TextShimmerLoader } from "@/components/prompt-kit/loader"; import { Audio } from "@/components/tool-ui/audio"; -import { Spinner } from "@/components/ui/spinner"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; import { baseApiService } from "@/lib/apis/base-api.service"; import { authenticatedFetch } from "@/lib/auth-utils"; import { clearActivePodcastTaskId, setActivePodcastTaskId } from "@/lib/chat/podcast-state"; @@ -92,82 +97,38 @@ function parsePodcastDetails(data: unknown): { podcast_transcript?: PodcastTrans }; } -/** - * Loading state component shown while podcast is being generated - */ function PodcastGeneratingState({ title }: { title: string }) { return ( -
-
-
-
- -
- {/* Animated rings */} -
-
-
-

- {title} -

-
- - - Generating podcast. This may take a few minutes. - -
-
-
-
-
-
-
+
+
+

{title}

+
); } -/** - * Error state component shown when podcast generation fails - */ function PodcastErrorState({ title, error }: { title: string; error: string }) { return ( -
-
-
- -
-
-

- {title} -

-

Failed to generate podcast

-

{error}

-
+
+
+

Podcast Generation Failed

+
+
+
+

{title}

+

{error}

); } -/** - * Audio loading state component - */ function AudioLoadingState({ title }: { title: string }) { return ( -
-
-
- -
-
-

- {title} -

-
- - Loading audio... -
-
+
+
+

{title}

+
); @@ -176,12 +137,10 @@ function AudioLoadingState({ title }: { title: string }) { function PodcastPlayer({ podcastId, title, - description, durationMs, }: { podcastId: number; title: string; - description: string; durationMs?: number; }) { const params = useParams(); @@ -289,31 +248,40 @@ function PodcastPlayer({ return ; } + const hasTranscript = transcript && transcript.length > 0; + return (