import { useEffect, useRef, useState, type RefObject } from "react"; import { artifactsApi, videoVoicesApi, type GenerateBody } from "../api/endpoints"; import type { Artifact, ChatSummary, Segment, VideoSavedVoice } from "../api/types"; import { useJob } from "../hooks/useJob"; import { Transcript } from "./ArtifactCard"; import { Dropdown } from "./Dropdown"; import { CheckIcon, ChevronIcon, HeadphonesIcon } from "./icons/Icons"; import { LANGUAGES, Pills, SourceFocusFields, type SourceSelection } from "./SourceFocusFields"; import { ConfirmDeleteModal, errorMessage, JobProgress, Modal, StatusPill } from "./ui"; /** The audio styles. The server describes each to the script writer (backend/app/pipeline/media.py STYLES). */ const STYLES = [ { id: "deep_dive", name: "Deep Dive", blurb: "A lively conversation that unpacks the ideas in your sources and connects them." }, { id: "brief", name: "Brief", blurb: "A bite sized overview to help you grasp the core ideas from your sources quickly." }, { id: "critique", name: "Critique", blurb: "An expert review of your sources, with constructive feedback to help you improve your material." }, { id: "debate", name: "Debate", blurb: "A thoughtful debate between two hosts, bringing out different perspectives on your sources." }, ] as const; type Style = (typeof STYLES)[number]["id"]; const LENGTHS = [ { value: "3", label: "Short", hint: "about 3 min" }, { value: "6", label: "Default", hint: "about 6 min" }, { value: "12", label: "Long", hint: "about 12 min" }, ]; export type AudioOverviewRequest = Omit; /** The workspace's voices, asked for once (the list takes a few seconds): the notebook asks ahead of time, so the * pickers are ready when the settings open. A failure is forgotten, so the next open asks again. */ let voicesAsked: Promise | null = null; export function prefetchVoices(): Promise { voicesAsked ??= videoVoicesApi.list().then((r) => r.saved).catch((e) => { voicesAsked = null; throw e; }); return voicesAsked; } /** The audio overview settings: a style, one or two hosts and their voices, length, language, the sources, and what * the hosts should focus on. */ export function AudioOverviewDialog({ notebookId, notebookTitle, chats, currentChatId, onClose, onCreate }: { notebookId: string; notebookTitle?: string; chats: ChatSummary[]; currentChatId?: string | null; onClose: () => void; onCreate: (body: AudioOverviewRequest) => void; }) { const [sel, setSel] = useState(null); const [style, setStyle] = useState