"use client" import { useEffect, useState, useTransition } from "react" import { useStore } from "@/app/state/useStore" import { cn } from "@/lib/utils" import { VideoGenerationModel, VideoInfo } from "@/types" import { useLocalStorage } from "usehooks-ts" import { localStorageKeys } from "@/app/state/localStorageKeys" import { defaultSettings } from "@/app/state/defaultSettings" import { Input } from "@/components/ui/input" import { Textarea } from "@/components/ui/textarea" import { Button } from "@/components/ui/button" import { submitVideoRequest } from "@/app/server/actions/submitVideoRequest" import { PendingVideoList } from "@/app/interface/pending-video-list" import { getChannelVideos } from "@/app/server/actions/ai-tube-hf/getChannelVideos" import { parseVideoModelName } from "@/app/server/actions/utils/parseVideoModelName" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { defaultVideoModel, defaultVoice } from "@/app/config" export function UserChannelView() { const [_isPending, startTransition] = useTransition() const [huggingfaceApiKey, setHuggingfaceApiKey] = useLocalStorage( localStorageKeys.huggingfaceApiKey, defaultSettings.huggingfaceApiKey ) const [titleDraft, setTitleDraft] = useState("") const [descriptionDraft, setDescriptionDraft] = useState("") const [tagsDraft, setTagsDraft] = useState("") const [promptDraft, setPromptDraft] = useState("") const [modelDraft, setModelDraft] = useState(defaultVideoModel) const [loraDraft, setLoraDraft] = useState("") const [styleDraft, setStyleDraft] = useState("") const [voiceDraft, setVoiceDraft] = useState(defaultVoice) const [musicDraft, setMusicDraft] = useState("") // we do not include the tags in the list of required fields const missingFields = !titleDraft || !descriptionDraft || !promptDraft const [isSubmitting, setIsSubmitting] = useState(false) const userChannel = useStore(s => s.userChannel) const userChannels = useStore(s => s.userChannels) const userVideos = useStore(s => s.userVideos) const setUserChannel = useStore(s => s.setUserChannel) const setUserChannels = useStore(s => s.setUserChannels) const setUserVideos = useStore(s => s.setUserVideos) useEffect(() => { if (!userChannel) { return } startTransition(async () => { const videos = await getChannelVideos({ channel: userChannel, // status: undefined, // we want *all* status }) console.log("setCurrentVideos:", videos) setUserVideos(videos) }) }, [huggingfaceApiKey, userChannel, userChannel?.id]) const handleSubmit = () => { if (!userChannel) { return } if (!titleDraft || !promptDraft) { console.log("missing title or prompt") return } setIsSubmitting(true) startTransition(async () => { try { const newVideo = await submitVideoRequest({ channel: userChannel, apiKey: huggingfaceApiKey, title: titleDraft, description: descriptionDraft, prompt: promptDraft, model: modelDraft, lora: loraDraft, style: styleDraft, voice: voiceDraft, music: musicDraft, tags: tagsDraft.trim().split(",").map(x => x.trim()).filter(x => x), }) // in case of success we update the frontend immediately // with our draft video setUserVideos([newVideo, ...userVideos]) setPromptDraft("") setDescriptionDraft("") setTagsDraft("") setTitleDraft("") setModelDraft(defaultVideoModel) setVoiceDraft(defaultVoice) setMusicDraft("") setLoraDraft("") setStyleDraft("") // also renew the cache on Next's side /* await getChannelVideos({ channel: currentChannel, apiKey: huggingfaceApiKey, renewCache: true, }) */ } catch (err) { console.error(err) } finally { setIsSubmitting(false) } }) } const handleDelete = (video: VideoInfo) => { // step 1: delete it from the dataset // step 2: if the video has already been generated, // we ask the robot to delete it from the index } return (

Robot channel settings:

TODO

Create a new AI video:

{ setTitleDraft(x.target.value) }} value={titleDraft} />