"use client" import { useEffect, useState, useTransition } from "react" import { defaultMediaOrientation, parseMediaOrientation } from "@aitube/clap" import { useLocalStorage } from "usehooks-ts" import { useStore } from "@/app/state/useStore" import { cn } from "@/lib/utils/cn" import { VideoGenerationModel, MediaInfo } from "@/types/general" 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/api/actions/submitVideoRequest" import { PendingVideoList } from "@/components/interface/pending-video-list" import { getChannelVideos } from "@/app/api/actions/ai-tube-hf/getChannelVideos" import { parseVideoModelName } from "@/app/api/parsers/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 [title, setTitle] = useState("") const [description, setDescription] = useState("") const [tags, setTags] = useState("") const [prompt, setPrompt] = useState("") const [model, setModel] = useState(defaultVideoModel) const [lora, setLora] = useState("") const [style, setStyle] = useState("") const [voice, setVoice] = useState(defaultVoice) const [music, setMusic] = useState("") const [duration, setDuration] = useState(0) const [orientation, setOrientation] = useState(defaultMediaOrientation) // we do not include the tags in the list of required fields const missingFields = !title || !description || !prompt 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 (!title || !prompt) { console.log("missing title or prompt") return } setIsSubmitting(true) startTransition(async () => { try { const newVideo = await submitVideoRequest({ channel: userChannel, apiKey: huggingfaceApiKey, title, description, prompt, model, lora, style, voice, music, tags: tags.trim().split(",").map(x => x.trim()).filter(x => x), duration, orientation }) // in case of success we update the frontend immediately // with our video setUserVideos([newVideo, ...userVideos]) setPrompt("") setDescription("") setTags("") setTitle("") setModel(defaultVideoModel) setVoice(defaultVoice) setMusic("") setLora("") setStyle("") // 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: MediaInfo) => { // 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:

{ setTitle(x.target.value) }} value={title} />