Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Commit
•
1185ec1
1
Parent(s):
e70dbb1
just a lil bit of plumbing
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- src/app/channel/page.tsx +1 -1
- src/app/config.ts +1 -1
- src/app/interface/channel-card/index.tsx +1 -1
- src/app/interface/channel-list/index.tsx +1 -1
- src/app/interface/collection-card/index.tsx +1 -1
- src/app/interface/collection-list/index.tsx +1 -1
- src/app/interface/comment-card/index.tsx +1 -1
- src/app/interface/comment-list/index.tsx +1 -1
- src/app/interface/equirectangular-video-player/index.tsx +1 -1
- src/app/interface/equirectangular-video-player/viewer.tsx +1 -1
- src/app/interface/like-button/index.tsx +1 -1
- src/app/interface/media-list/index.tsx +1 -1
- src/app/interface/pending-video-card/index.tsx +1 -1
- src/app/interface/pending-video-list/index.tsx +1 -1
- src/app/interface/playlist-control/index.tsx +1 -1
- src/app/interface/recommended-videos/index.tsx +1 -1
- src/app/interface/track-card/index.tsx +1 -1
- src/app/interface/video-card/index.tsx +1 -1
- src/app/interface/video-player/cartesian.tsx +1 -1
- src/app/interface/video-player/equirectangular.tsx +1 -1
- src/app/interface/video-player/index.tsx +1 -1
- src/app/main.tsx +1 -1
- src/app/music/page.tsx +1 -1
- src/app/page.tsx +1 -1
- src/app/playlist/page.tsx +1 -1
- src/app/server/actions/ai-tube-hf/deleteVideoRequest.ts +1 -1
- src/app/server/actions/ai-tube-hf/downloadClapProject.ts +99 -0
- src/app/server/actions/ai-tube-hf/downloadFileAsBlob.ts +63 -0
- src/app/server/actions/ai-tube-hf/downloadPlainText.ts +13 -0
- src/app/server/actions/ai-tube-hf/extendVideosWithStats.ts +1 -1
- src/app/server/actions/ai-tube-hf/getChannel.ts +1 -1
- src/app/server/actions/ai-tube-hf/getChannelVideos.ts +13 -10
- src/app/server/actions/ai-tube-hf/getChannels.ts +1 -1
- src/app/server/actions/ai-tube-hf/getPrivateChannels.ts +1 -1
- src/app/server/actions/ai-tube-hf/getVideo.ts +1 -1
- src/app/server/actions/ai-tube-hf/getVideoIndex.ts +1 -1
- src/app/server/actions/ai-tube-hf/getVideoRequestsFromChannel.ts +108 -81
- src/app/server/actions/ai-tube-hf/getVideos.ts +1 -1
- src/app/server/actions/ai-tube-hf/parseChannel.ts +1 -1
- src/app/server/actions/ai-tube-hf/uploadVideoRequestToDataset.ts +10 -1
- src/app/server/actions/ai-tube-robot/updateQueue.ts +1 -1
- src/app/server/actions/comments.ts +1 -1
- src/app/server/actions/stats.ts +1 -1
- src/app/server/actions/submitVideoRequest.ts +1 -1
- src/app/server/actions/users.ts +1 -1
- src/app/server/actions/utils/computeOrientationProjectionWidthHeight.ts +1 -1
- src/app/server/actions/utils/isAntisocial.ts +1 -1
- src/app/server/actions/utils/isHighQuality.ts +1 -1
- src/app/server/actions/utils/parseClap.ts +91 -0
- src/app/server/actions/utils/parseDatasetPrompt.ts +1 -1
src/app/channel/page.tsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { AppQueryProps } from "@/types"
|
2 |
|
3 |
import { Main } from "../main"
|
4 |
import { getChannel } from "../server/actions/ai-tube-hf/getChannel"
|
|
|
1 |
+
import { AppQueryProps } from "@/types/general"
|
2 |
|
3 |
import { Main } from "../main"
|
4 |
import { getChannel } from "../server/actions/ai-tube-hf/getChannel"
|
src/app/config.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { VideoGenerationModel, VideoOrientation } from "@/types"
|
2 |
|
3 |
export const showBetaFeatures = `${
|
4 |
process.env.NEXT_PUBLIC_SHOW_BETA_FEATURES || ""
|
|
|
1 |
+
import { VideoGenerationModel, VideoOrientation } from "@/types/general"
|
2 |
|
3 |
export const showBetaFeatures = `${
|
4 |
process.env.NEXT_PUBLIC_SHOW_BETA_FEATURES || ""
|
src/app/interface/channel-card/index.tsx
CHANGED
@@ -4,7 +4,7 @@ import { RiCheckboxCircleFill } from "react-icons/ri"
|
|
4 |
import { IoAdd } from "react-icons/io5"
|
5 |
|
6 |
import { cn } from "@/lib/utils"
|
7 |
-
import { ChannelInfo } from "@/types"
|
8 |
import { isCertifiedUser } from "@/app/certification"
|
9 |
import { DefaultAvatar } from "../default-avatar"
|
10 |
import { formatLargeNumber } from "@/lib/formatLargeNumber"
|
|
|
4 |
import { IoAdd } from "react-icons/io5"
|
5 |
|
6 |
import { cn } from "@/lib/utils"
|
7 |
+
import { ChannelInfo } from "@/types/general"
|
8 |
import { isCertifiedUser } from "@/app/certification"
|
9 |
import { DefaultAvatar } from "../default-avatar"
|
10 |
import { formatLargeNumber } from "@/lib/formatLargeNumber"
|
src/app/interface/channel-list/index.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
-
import { ChannelInfo } from "@/types"
|
3 |
|
4 |
import { ChannelCard } from "../channel-card"
|
5 |
|
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
+
import { ChannelInfo } from "@/types/general"
|
3 |
|
4 |
import { ChannelCard } from "../channel-card"
|
5 |
|
src/app/interface/collection-card/index.tsx
CHANGED
@@ -5,7 +5,7 @@ import Link from "next/link"
|
|
5 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
6 |
|
7 |
import { cn } from "@/lib/utils"
|
8 |
-
import { CollectionInfo } from "@/types"
|
9 |
import { formatDuration } from "@/lib/formatDuration"
|
10 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
11 |
import { isCertifiedUser } from "@/app/certification"
|
|
|
5 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
6 |
|
7 |
import { cn } from "@/lib/utils"
|
8 |
+
import { CollectionInfo } from "@/types/general"
|
9 |
import { formatDuration } from "@/lib/formatDuration"
|
10 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
11 |
import { isCertifiedUser } from "@/app/certification"
|
src/app/interface/collection-list/index.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
-
import { CollectionInfo } from "@/types"
|
3 |
|
4 |
import { CollectionCard } from "../collection-card"
|
5 |
|
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
+
import { CollectionInfo } from "@/types/general"
|
3 |
|
4 |
import { CollectionCard } from "../collection-card"
|
5 |
|
src/app/interface/comment-card/index.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
-
import { CommentInfo } from "@/types"
|
3 |
import { useEffect, useState } from "react"
|
4 |
import { DefaultAvatar } from "../default-avatar"
|
5 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
+
import { CommentInfo } from "@/types/general"
|
3 |
import { useEffect, useState } from "react"
|
4 |
import { DefaultAvatar } from "../default-avatar"
|
5 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
src/app/interface/comment-list/index.tsx
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
"use client"
|
2 |
|
3 |
import { cn } from "@/lib/utils"
|
4 |
-
import { CommentInfo } from "@/types"
|
5 |
import { CommentCard } from "../comment-card"
|
6 |
|
7 |
export function CommentList({
|
|
|
1 |
"use client"
|
2 |
|
3 |
import { cn } from "@/lib/utils"
|
4 |
+
import { CommentInfo } from "@/types/general"
|
5 |
import { CommentCard } from "../comment-card"
|
6 |
|
7 |
export function CommentList({
|
src/app/interface/equirectangular-video-player/index.tsx
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
import AutoSizer from "react-virtualized-auto-sizer"
|
4 |
|
5 |
import { cn } from "@/lib/utils"
|
6 |
-
import { VideoInfo } from "@/types"
|
7 |
|
8 |
import { VideoSphereViewer } from "./viewer"
|
9 |
|
|
|
3 |
import AutoSizer from "react-virtualized-auto-sizer"
|
4 |
|
5 |
import { cn } from "@/lib/utils"
|
6 |
+
import { VideoInfo } from "@/types/general"
|
7 |
|
8 |
import { VideoSphereViewer } from "./viewer"
|
9 |
|
src/app/interface/equirectangular-video-player/viewer.tsx
CHANGED
@@ -6,7 +6,7 @@ import { PanoramaPosition, PluginConstructor, Point, Position, SphericalPosition
|
|
6 |
import { EquirectangularVideoAdapter, LensflarePlugin, ReactPhotoSphereViewer, ResolutionPlugin, SettingsPlugin, VideoPlugin } from "react-photo-sphere-viewer"
|
7 |
|
8 |
import { cn } from "@/lib/utils"
|
9 |
-
import { VideoInfo } from "@/types"
|
10 |
|
11 |
type PhotoSpherePlugin = (PluginConstructor | [PluginConstructor, any])
|
12 |
|
|
|
6 |
import { EquirectangularVideoAdapter, LensflarePlugin, ReactPhotoSphereViewer, ResolutionPlugin, SettingsPlugin, VideoPlugin } from "react-photo-sphere-viewer"
|
7 |
|
8 |
import { cn } from "@/lib/utils"
|
9 |
+
import { VideoInfo } from "@/types/general"
|
10 |
|
11 |
type PhotoSpherePlugin = (PluginConstructor | [PluginConstructor, any])
|
12 |
|
src/app/interface/like-button/index.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { useEffect, useState, useTransition } from "react"
|
2 |
-
import { VideoInfo, VideoRating } from "@/types"
|
3 |
|
4 |
import { GenericLikeButton } from "./generic"
|
5 |
import { getVideoRating, rateVideo } from "@/app/server/actions/stats"
|
|
|
1 |
import { useEffect, useState, useTransition } from "react"
|
2 |
+
import { VideoInfo, VideoRating } from "@/types/general"
|
3 |
|
4 |
import { GenericLikeButton } from "./generic"
|
5 |
import { getVideoRating, rateVideo } from "@/app/server/actions/stats"
|
src/app/interface/media-list/index.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
-
import { MediaDisplayLayout, VideoInfo } from "@/types"
|
3 |
import { TrackCard } from "../track-card"
|
4 |
import { VideoCard } from "../video-card"
|
5 |
|
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
+
import { MediaDisplayLayout, VideoInfo } from "@/types/general"
|
3 |
import { TrackCard } from "../track-card"
|
4 |
import { VideoCard } from "../video-card"
|
5 |
|
src/app/interface/pending-video-card/index.tsx
CHANGED
@@ -3,7 +3,7 @@ import { PiTrashBold } from "react-icons/pi"
|
|
3 |
import { TableCell, TableRow } from "@/components/ui/table"
|
4 |
import { cn } from "@/lib/utils"
|
5 |
import { MdLockClock } from "react-icons/md"
|
6 |
-
import { VideoInfo } from "@/types"
|
7 |
import { truncate } from "./truncate"
|
8 |
|
9 |
export function PendingVideoCard({
|
|
|
3 |
import { TableCell, TableRow } from "@/components/ui/table"
|
4 |
import { cn } from "@/lib/utils"
|
5 |
import { MdLockClock } from "react-icons/md"
|
6 |
+
import { VideoInfo } from "@/types/general"
|
7 |
import { truncate } from "./truncate"
|
8 |
|
9 |
export function PendingVideoCard({
|
src/app/interface/pending-video-list/index.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
-
import { VideoInfo } from "@/types"
|
3 |
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
4 |
|
5 |
import { PendingVideoCard } from "../pending-video-card"
|
|
|
1 |
import { cn } from "@/lib/utils"
|
2 |
+
import { VideoInfo } from "@/types/general"
|
3 |
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
4 |
|
5 |
import { PendingVideoCard } from "../pending-video-card"
|
src/app/interface/playlist-control/index.tsx
CHANGED
@@ -3,7 +3,7 @@ import { IoIosPause } from "react-icons/io"
|
|
3 |
|
4 |
import { cn } from "@/lib/utils"
|
5 |
import { usePlaylist } from "@/lib/usePlaylist"
|
6 |
-
import { VideoInfo } from "@/types"
|
7 |
|
8 |
export function PlaylistControl() {
|
9 |
const playlist = usePlaylist()
|
|
|
3 |
|
4 |
import { cn } from "@/lib/utils"
|
5 |
import { usePlaylist } from "@/lib/usePlaylist"
|
6 |
+
import { VideoInfo } from "@/types/general"
|
7 |
|
8 |
export function PlaylistControl() {
|
9 |
const playlist = usePlaylist()
|
src/app/interface/recommended-videos/index.tsx
CHANGED
@@ -3,7 +3,7 @@ import { useEffect, useTransition } from "react"
|
|
3 |
|
4 |
import { useStore } from "@/app/state/useStore"
|
5 |
import { cn } from "@/lib/utils"
|
6 |
-
import { VideoInfo } from "@/types"
|
7 |
|
8 |
import { VideoList } from "../video-list"
|
9 |
import { getVideos } from "@/app/server/actions/ai-tube-hf/getVideos"
|
|
|
3 |
|
4 |
import { useStore } from "@/app/state/useStore"
|
5 |
import { cn } from "@/lib/utils"
|
6 |
+
import { VideoInfo } from "@/types/general"
|
7 |
|
8 |
import { VideoList } from "../video-list"
|
9 |
import { getVideos } from "@/app/server/actions/ai-tube-hf/getVideos"
|
src/app/interface/track-card/index.tsx
CHANGED
@@ -5,7 +5,7 @@ import Link from "next/link"
|
|
5 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
6 |
|
7 |
import { cn } from "@/lib/utils"
|
8 |
-
import { MediaDisplayLayout, VideoInfo } from "@/types"
|
9 |
import { formatDuration } from "@/lib/formatDuration"
|
10 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
11 |
import { isCertifiedUser } from "@/app/certification"
|
|
|
5 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
6 |
|
7 |
import { cn } from "@/lib/utils"
|
8 |
+
import { MediaDisplayLayout, VideoInfo } from "@/types/general"
|
9 |
import { formatDuration } from "@/lib/formatDuration"
|
10 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
11 |
import { isCertifiedUser } from "@/app/certification"
|
src/app/interface/video-card/index.tsx
CHANGED
@@ -5,7 +5,7 @@ import Link from "next/link"
|
|
5 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
6 |
|
7 |
import { cn } from "@/lib/utils"
|
8 |
-
import { MediaDisplayLayout, VideoInfo } from "@/types"
|
9 |
import { formatDuration } from "@/lib/formatDuration"
|
10 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
11 |
import { isCertifiedUser } from "@/app/certification"
|
|
|
5 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
6 |
|
7 |
import { cn } from "@/lib/utils"
|
8 |
+
import { MediaDisplayLayout, VideoInfo } from "@/types/general"
|
9 |
import { formatDuration } from "@/lib/formatDuration"
|
10 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
11 |
import { isCertifiedUser } from "@/app/certification"
|
src/app/interface/video-player/cartesian.tsx
CHANGED
@@ -4,7 +4,7 @@ import { Player } from "react-tuby"
|
|
4 |
import "react-tuby/css/main.css"
|
5 |
|
6 |
import { cn } from "@/lib/utils"
|
7 |
-
import { VideoInfo } from "@/types"
|
8 |
|
9 |
export function CartesianVideoPlayer({
|
10 |
video,
|
|
|
4 |
import "react-tuby/css/main.css"
|
5 |
|
6 |
import { cn } from "@/lib/utils"
|
7 |
+
import { VideoInfo } from "@/types/general"
|
8 |
|
9 |
export function CartesianVideoPlayer({
|
10 |
video,
|
src/app/interface/video-player/equirectangular.tsx
CHANGED
@@ -6,7 +6,7 @@ import { PanoramaPosition, PluginConstructor, Point, Position, SphericalPosition
|
|
6 |
import { EquirectangularVideoAdapter, LensflarePlugin, ReactPhotoSphereViewer, ResolutionPlugin, SettingsPlugin, VideoPlugin } from "react-photo-sphere-viewer"
|
7 |
|
8 |
import { cn } from "@/lib/utils"
|
9 |
-
import { VideoInfo } from "@/types"
|
10 |
|
11 |
type PhotoSpherePlugin = (PluginConstructor | [PluginConstructor, any])
|
12 |
|
|
|
6 |
import { EquirectangularVideoAdapter, LensflarePlugin, ReactPhotoSphereViewer, ResolutionPlugin, SettingsPlugin, VideoPlugin } from "react-photo-sphere-viewer"
|
7 |
|
8 |
import { cn } from "@/lib/utils"
|
9 |
+
import { VideoInfo } from "@/types/general"
|
10 |
|
11 |
type PhotoSpherePlugin = (PluginConstructor | [PluginConstructor, any])
|
12 |
|
src/app/interface/video-player/index.tsx
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
import AutoSizer from "react-virtualized-auto-sizer"
|
4 |
|
5 |
import { cn } from "@/lib/utils"
|
6 |
-
import { VideoInfo } from "@/types"
|
7 |
import { parseProjectionFromLoRA } from "@/app/server/actions/utils/parseProjectionFromLoRA"
|
8 |
|
9 |
import { EquirectangularVideoPlayer } from "./equirectangular"
|
|
|
3 |
import AutoSizer from "react-virtualized-auto-sizer"
|
4 |
|
5 |
import { cn } from "@/lib/utils"
|
6 |
+
import { VideoInfo } from "@/types/general"
|
7 |
import { parseProjectionFromLoRA } from "@/app/server/actions/utils/parseProjectionFromLoRA"
|
8 |
|
9 |
import { EquirectangularVideoPlayer } from "./equirectangular"
|
src/app/main.tsx
CHANGED
@@ -8,7 +8,7 @@ import { UserChannelView } from "./views/user-channel-view"
|
|
8 |
import { PublicVideoView } from "./views/public-video-view"
|
9 |
import { UserAccountView } from "./views/user-account-view"
|
10 |
import { NotFoundView } from "./views/not-found-view"
|
11 |
-
import { ChannelInfo, InterfaceView, VideoInfo } from "@/types"
|
12 |
import { useEffect } from "react"
|
13 |
import { usePathname, useRouter } from "next/navigation"
|
14 |
import { TubeLayout } from "./interface/tube-layout"
|
|
|
8 |
import { PublicVideoView } from "./views/public-video-view"
|
9 |
import { UserAccountView } from "./views/user-account-view"
|
10 |
import { NotFoundView } from "./views/not-found-view"
|
11 |
+
import { ChannelInfo, InterfaceView, VideoInfo } from "@/types/general"
|
12 |
import { useEffect } from "react"
|
13 |
import { usePathname, useRouter } from "next/navigation"
|
14 |
import { TubeLayout } from "./interface/tube-layout"
|
src/app/music/page.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
|
2 |
-
import { AppQueryProps } from "@/types"
|
3 |
import { Main } from "../main"
|
4 |
import { getVideos } from "../server/actions/ai-tube-hf/getVideos"
|
5 |
import { getVideo } from "../server/actions/ai-tube-hf/getVideo"
|
|
|
1 |
|
2 |
+
import { AppQueryProps } from "@/types/general"
|
3 |
import { Main } from "../main"
|
4 |
import { getVideos } from "../server/actions/ai-tube-hf/getVideos"
|
5 |
import { getVideo } from "../server/actions/ai-tube-hf/getVideo"
|
src/app/page.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
|
2 |
-
import { AppQueryProps } from "@/types"
|
3 |
|
4 |
import { Main } from "./main"
|
5 |
import { getVideo } from "./server/actions/ai-tube-hf/getVideo"
|
|
|
1 |
|
2 |
+
import { AppQueryProps } from "@/types/general"
|
3 |
|
4 |
import { Main } from "./main"
|
5 |
import { getVideo } from "./server/actions/ai-tube-hf/getVideo"
|
src/app/playlist/page.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
|
2 |
-
import { AppQueryProps } from "@/types"
|
3 |
import { Main } from "../main"
|
4 |
import { getVideos } from "../server/actions/ai-tube-hf/getVideos"
|
5 |
import { getVideo } from "../server/actions/ai-tube-hf/getVideo"
|
|
|
1 |
|
2 |
+
import { AppQueryProps } from "@/types/general"
|
3 |
import { Main } from "../main"
|
4 |
import { getVideos } from "../server/actions/ai-tube-hf/getVideos"
|
5 |
import { getVideo } from "../server/actions/ai-tube-hf/getVideo"
|
src/app/server/actions/ai-tube-hf/deleteVideoRequest.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
|
2 |
-
import { VideoInfo } from "@/types"
|
3 |
|
4 |
import { deleteFileFromDataset } from "./deleteFileFromDataset"
|
5 |
import { formatPromptFileName } from "../utils/formatPromptFileName"
|
|
|
1 |
|
2 |
+
import { VideoInfo } from "@/types/general"
|
3 |
|
4 |
import { deleteFileFromDataset } from "./deleteFileFromDataset"
|
5 |
import { formatPromptFileName } from "../utils/formatPromptFileName"
|
src/app/server/actions/ai-tube-hf/downloadClapProject.ts
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { v4 as uuidv4 } from "uuid"
|
2 |
+
|
3 |
+
import { ClapProject } from "@/types/clap"
|
4 |
+
import { ChannelInfo, VideoInfo, VideoRequest } from "@/types/general"
|
5 |
+
import { defaultVideoModel } from "@/app/config"
|
6 |
+
|
7 |
+
import { parseClap } from "../utils/parseClap"
|
8 |
+
import { parseVideoModelName } from "../utils/parseVideoModelName"
|
9 |
+
import { computeOrientationProjectionWidthHeight } from "../utils/computeOrientationProjectionWidthHeight"
|
10 |
+
|
11 |
+
import { downloadFileAsText } from "./downloadFileAsText"
|
12 |
+
import { downloadFileAsBlob } from "./downloadFileAsBlob"
|
13 |
+
|
14 |
+
export async function downloadClapProject({
|
15 |
+
path,
|
16 |
+
apiKey,
|
17 |
+
channel
|
18 |
+
}: {
|
19 |
+
path: string
|
20 |
+
apiKey?: string
|
21 |
+
channel: ChannelInfo
|
22 |
+
}): Promise<{
|
23 |
+
videoRequest: VideoRequest
|
24 |
+
videoInfo: VideoInfo
|
25 |
+
clapProject: ClapProject
|
26 |
+
}> {
|
27 |
+
// we recover the repo from the cnannel info
|
28 |
+
const repo = `datasets/${channel.datasetUser}/${channel.datasetName}`
|
29 |
+
|
30 |
+
// we download the clap file (which might be in a private repo)
|
31 |
+
const clapString = await downloadFileAsBlob({
|
32 |
+
repo,
|
33 |
+
path,
|
34 |
+
apiKey,
|
35 |
+
expectedMimeType: "application/gzip"
|
36 |
+
})
|
37 |
+
|
38 |
+
const clapProject = await parseClap(clapString)
|
39 |
+
|
40 |
+
const id = uuidv4()
|
41 |
+
|
42 |
+
const videoRequest: VideoRequest = {
|
43 |
+
id,
|
44 |
+
label: clapProject.meta.title || "Untitled",
|
45 |
+
description: clapProject.meta.description || "",
|
46 |
+
prompt: "", // there is no prompt - instead we use segments
|
47 |
+
model: parseVideoModelName(clapProject.meta.defaultVideoModel, channel.model),
|
48 |
+
style: channel.style,
|
49 |
+
lora: channel.lora,
|
50 |
+
voice: channel.voice,
|
51 |
+
music: channel.music,
|
52 |
+
thumbnailUrl: "",
|
53 |
+
clapUrl: `https://huggingface.co/${repo}/resolve/main/${path}`,
|
54 |
+
updatedAt: new Date().toISOString(),
|
55 |
+
tags: channel.tags,
|
56 |
+
channel,
|
57 |
+
duration: 0, // will be computed automatically
|
58 |
+
...computeOrientationProjectionWidthHeight({
|
59 |
+
lora: "",
|
60 |
+
orientation: clapProject.meta.orientation,
|
61 |
+
// projection, // <- will be extrapolated from the LoRA for now
|
62 |
+
}),
|
63 |
+
}
|
64 |
+
|
65 |
+
const videoInfo: VideoInfo = {
|
66 |
+
id,
|
67 |
+
status: "submitted",
|
68 |
+
label: videoRequest.label || "",
|
69 |
+
description: videoRequest.description || "",
|
70 |
+
prompt: videoRequest.prompt || "",
|
71 |
+
model: videoRequest.model || defaultVideoModel,
|
72 |
+
style: videoRequest.style || "",
|
73 |
+
lora: videoRequest.lora || "",
|
74 |
+
voice: videoRequest.voice || "",
|
75 |
+
music: videoRequest.music || "",
|
76 |
+
thumbnailUrl: videoRequest.thumbnailUrl || "", // will be generated in async
|
77 |
+
clapUrl: videoRequest.clapUrl || "",
|
78 |
+
assetUrl: "", // will be generated in async
|
79 |
+
assetUrlHd: "",
|
80 |
+
numberOfViews: 0,
|
81 |
+
numberOfLikes: 0,
|
82 |
+
numberOfDislikes: 0,
|
83 |
+
updatedAt: new Date().toISOString(),
|
84 |
+
tags: videoRequest.tags,
|
85 |
+
channel,
|
86 |
+
duration: videoRequest.duration || 0,
|
87 |
+
...computeOrientationProjectionWidthHeight({
|
88 |
+
lora: videoRequest.lora,
|
89 |
+
orientation: videoRequest.orientation,
|
90 |
+
// projection, // <- will be extrapolated from the LoRA for now
|
91 |
+
}),
|
92 |
+
}
|
93 |
+
|
94 |
+
return {
|
95 |
+
videoRequest,
|
96 |
+
videoInfo,
|
97 |
+
clapProject
|
98 |
+
}
|
99 |
+
}
|
src/app/server/actions/ai-tube-hf/downloadFileAsBlob.ts
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { downloadFile } from "@/huggingface/hub/src"
|
2 |
+
import { getCredentials } from "./getCredentials"
|
3 |
+
|
4 |
+
export async function downloadFileAsBlob({
|
5 |
+
repo,
|
6 |
+
path,
|
7 |
+
apiKey,
|
8 |
+
expectedMimeType = "text/plain",
|
9 |
+
renewCache = false,
|
10 |
+
neverThrow = false
|
11 |
+
}: {
|
12 |
+
repo: string
|
13 |
+
|
14 |
+
path: string
|
15 |
+
|
16 |
+
apiKey?: string
|
17 |
+
|
18 |
+
expectedMimeType?: string
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Force renewing the cache
|
22 |
+
*
|
23 |
+
* False by default
|
24 |
+
*/
|
25 |
+
renewCache?: boolean
|
26 |
+
|
27 |
+
/**
|
28 |
+
* If set to true, this function will never throw an exception
|
29 |
+
* this is useful in workflow where we don't care about what happened
|
30 |
+
*
|
31 |
+
* False by default
|
32 |
+
*/
|
33 |
+
neverThrow?: boolean
|
34 |
+
}): Promise<Blob> {
|
35 |
+
try {
|
36 |
+
const { credentials } = await getCredentials(apiKey)
|
37 |
+
|
38 |
+
const response = await downloadFile({
|
39 |
+
repo,
|
40 |
+
path,
|
41 |
+
credentials,
|
42 |
+
requestInit: renewCache
|
43 |
+
? { cache: "no-cache" }
|
44 |
+
: undefined
|
45 |
+
})
|
46 |
+
|
47 |
+
if (!response) {
|
48 |
+
throw new Error("missing response")
|
49 |
+
}
|
50 |
+
const blob = await response.blob()
|
51 |
+
|
52 |
+
return blob
|
53 |
+
} catch (err) {
|
54 |
+
if (neverThrow) {
|
55 |
+
console.error(`downloadFileAsBlob():`, err)
|
56 |
+
|
57 |
+
const blobResult = new Blob([""], { type: expectedMimeType })
|
58 |
+
return blobResult
|
59 |
+
} else {
|
60 |
+
throw err
|
61 |
+
}
|
62 |
+
}
|
63 |
+
}
|
src/app/server/actions/ai-tube-hf/downloadPlainText.ts
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
export async function downloadPlainText(url: string): Promise<string> {
|
3 |
+
// Fetch the plain text file
|
4 |
+
const response = await fetch(url)
|
5 |
+
|
6 |
+
if (!response.ok) {
|
7 |
+
throw new Error(`Failed to download the plain/text file: ${response.statusText}`)
|
8 |
+
}
|
9 |
+
|
10 |
+
const plainText = await response.text()
|
11 |
+
|
12 |
+
return plainText
|
13 |
+
}
|
src/app/server/actions/ai-tube-hf/extendVideosWithStats.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
"use server"
|
2 |
|
3 |
-
import { VideoInfo } from "@/types"
|
4 |
|
5 |
import { getStatsForVideos } from "../stats"
|
6 |
|
|
|
1 |
"use server"
|
2 |
|
3 |
+
import { VideoInfo } from "@/types/general"
|
4 |
|
5 |
import { getStatsForVideos } from "../stats"
|
6 |
|
src/app/server/actions/ai-tube-hf/getChannel.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
"use server"
|
2 |
|
3 |
|
4 |
-
import { ChannelInfo } from "@/types"
|
5 |
|
6 |
import { getChannels } from "./getChannels"
|
7 |
|
|
|
1 |
"use server"
|
2 |
|
3 |
|
4 |
+
import { ChannelInfo } from "@/types/general"
|
5 |
|
6 |
import { getChannels } from "./getChannels"
|
7 |
|
src/app/server/actions/ai-tube-hf/getChannelVideos.ts
CHANGED
@@ -1,12 +1,13 @@
|
|
1 |
"use server"
|
2 |
|
3 |
-
import { ChannelInfo, VideoInfo, VideoStatus } from "@/types"
|
4 |
|
5 |
import { getVideoRequestsFromChannel } from "./getVideoRequestsFromChannel"
|
6 |
import { adminApiKey } from "../config"
|
7 |
import { getVideoIndex } from "./getVideoIndex"
|
8 |
import { extendVideosWithStats } from "./extendVideosWithStats"
|
9 |
import { computeOrientationProjectionWidthHeight } from "../utils/computeOrientationProjectionWidthHeight"
|
|
|
10 |
|
11 |
// return
|
12 |
export async function getChannelVideos({
|
@@ -40,16 +41,18 @@ export async function getChannelVideos({
|
|
40 |
let video: VideoInfo = {
|
41 |
id: v.id,
|
42 |
status: "submitted",
|
43 |
-
label: v.label,
|
44 |
-
description: v.description,
|
45 |
-
prompt: v.prompt,
|
46 |
-
thumbnailUrl: v.thumbnailUrl,
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
|
|
52 |
assetUrl: "",
|
|
|
53 |
numberOfViews: 0,
|
54 |
numberOfLikes: 0,
|
55 |
numberOfDislikes: 0,
|
|
|
1 |
"use server"
|
2 |
|
3 |
+
import { ChannelInfo, VideoInfo, VideoStatus } from "@/types/general"
|
4 |
|
5 |
import { getVideoRequestsFromChannel } from "./getVideoRequestsFromChannel"
|
6 |
import { adminApiKey } from "../config"
|
7 |
import { getVideoIndex } from "./getVideoIndex"
|
8 |
import { extendVideosWithStats } from "./extendVideosWithStats"
|
9 |
import { computeOrientationProjectionWidthHeight } from "../utils/computeOrientationProjectionWidthHeight"
|
10 |
+
import { defaultVideoModel } from "@/app/config"
|
11 |
|
12 |
// return
|
13 |
export async function getChannelVideos({
|
|
|
41 |
let video: VideoInfo = {
|
42 |
id: v.id,
|
43 |
status: "submitted",
|
44 |
+
label: v.label || "",
|
45 |
+
description: v.description || "",
|
46 |
+
prompt: v.prompt || "",
|
47 |
+
thumbnailUrl: v.thumbnailUrl || "",
|
48 |
+
clapUrl: v.clapUrl || "",
|
49 |
+
model: v.model || defaultVideoModel,
|
50 |
+
lora: v.lora || "",
|
51 |
+
style: v.style || "",
|
52 |
+
voice: v.voice || "",
|
53 |
+
music: v.music || "",
|
54 |
assetUrl: "",
|
55 |
+
assetUrlHd: "",
|
56 |
numberOfViews: 0,
|
57 |
numberOfLikes: 0,
|
58 |
numberOfDislikes: 0,
|
src/app/server/actions/ai-tube-hf/getChannels.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
"use server"
|
2 |
|
3 |
-
import { ChannelInfo } from "@/types"
|
4 |
|
5 |
import { adminUsername } from "../config"
|
6 |
|
|
|
1 |
"use server"
|
2 |
|
3 |
+
import { ChannelInfo } from "@/types/general"
|
4 |
|
5 |
import { adminUsername } from "../config"
|
6 |
|
src/app/server/actions/ai-tube-hf/getPrivateChannels.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
"use server"
|
2 |
|
3 |
import { Credentials, listDatasets, whoAmI } from "@/huggingface/hub/src"
|
4 |
-
import { ChannelInfo } from "@/types"
|
5 |
|
6 |
import { adminCredentials } from "../config"
|
7 |
import { parseChannel } from "./parseChannel"
|
|
|
1 |
"use server"
|
2 |
|
3 |
import { Credentials, listDatasets, whoAmI } from "@/huggingface/hub/src"
|
4 |
+
import { ChannelInfo } from "@/types/general"
|
5 |
|
6 |
import { adminCredentials } from "../config"
|
7 |
import { parseChannel } from "./parseChannel"
|
src/app/server/actions/ai-tube-hf/getVideo.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
"use server"
|
2 |
|
3 |
-
import { VideoInfo } from "@/types"
|
4 |
|
5 |
import { getVideoIndex } from "./getVideoIndex"
|
6 |
import { getStatsForVideos } from "../stats"
|
|
|
1 |
"use server"
|
2 |
|
3 |
+
import { VideoInfo } from "@/types/general"
|
4 |
|
5 |
import { getVideoIndex } from "./getVideoIndex"
|
6 |
import { getStatsForVideos } from "../stats"
|
src/app/server/actions/ai-tube-hf/getVideoIndex.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { VideoInfo, VideoStatus } from "@/types"
|
2 |
|
3 |
import { adminUsername } from "../config"
|
4 |
|
|
|
1 |
+
import { VideoInfo, VideoStatus } from "@/types/general"
|
2 |
|
3 |
import { adminUsername } from "../config"
|
4 |
|
src/app/server/actions/ai-tube-hf/getVideoRequestsFromChannel.ts
CHANGED
@@ -1,12 +1,13 @@
|
|
1 |
"use server"
|
2 |
|
3 |
-
import { ChannelInfo, VideoRequest } from "@/types"
|
4 |
import { getCredentials } from "./getCredentials"
|
5 |
import { listFiles } from "@/huggingface/hub/src"
|
6 |
import { parsePromptFileName } from "../utils/parsePromptFileName"
|
7 |
import { downloadFileAsText } from "./downloadFileAsText"
|
8 |
import { parseDatasetPrompt } from "../utils/parseDatasetPrompt"
|
9 |
import { computeOrientationProjectionWidthHeight } from "../utils/computeOrientationProjectionWidthHeight"
|
|
|
10 |
|
11 |
/**
|
12 |
* Return all the videos requests created by a user on their channel
|
@@ -42,89 +43,115 @@ export async function getVideoRequestsFromChannel({
|
|
42 |
? { cache: "no-cache" }
|
43 |
: undefined
|
44 |
})) {
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
thumbnail.startsWith("http")
|
96 |
-
? thumbnail
|
97 |
-
: (thumbnail.endsWith(".jpg") || thumbnail.endsWith(".jpeg"))
|
98 |
-
? `https://huggingface.co/${repo}/resolve/main/${thumbnail}`
|
99 |
-
: ""
|
100 |
-
|
101 |
-
|
102 |
-
const video: VideoRequest = {
|
103 |
-
id,
|
104 |
-
label: title,
|
105 |
-
description,
|
106 |
-
prompt,
|
107 |
-
thumbnailUrl,
|
108 |
-
model,
|
109 |
-
lora,
|
110 |
-
style,
|
111 |
-
voice,
|
112 |
-
music,
|
113 |
-
updatedAt: file.lastCommit?.date || new Date().toISOString(),
|
114 |
-
tags: Array.isArray(tags) && tags.length ? tags : channel.tags,
|
115 |
-
channel,
|
116 |
-
duration: 0,
|
117 |
-
...computeOrientationProjectionWidthHeight({
|
118 |
lora,
|
|
|
|
|
|
|
119 |
orientation,
|
120 |
-
|
121 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
}
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
} else if (file.path.endsWith(".mp4")) {
|
127 |
-
// console.log("found a video:", file.path)
|
128 |
}
|
129 |
}
|
130 |
|
|
|
1 |
"use server"
|
2 |
|
3 |
+
import { ChannelInfo, VideoRequest } from "@/types/general"
|
4 |
import { getCredentials } from "./getCredentials"
|
5 |
import { listFiles } from "@/huggingface/hub/src"
|
6 |
import { parsePromptFileName } from "../utils/parsePromptFileName"
|
7 |
import { downloadFileAsText } from "./downloadFileAsText"
|
8 |
import { parseDatasetPrompt } from "../utils/parseDatasetPrompt"
|
9 |
import { computeOrientationProjectionWidthHeight } from "../utils/computeOrientationProjectionWidthHeight"
|
10 |
+
import { downloadClapProject } from "./downloadClapProject"
|
11 |
|
12 |
/**
|
13 |
* Return all the videos requests created by a user on their channel
|
|
|
43 |
? { cache: "no-cache" }
|
44 |
: undefined
|
45 |
})) {
|
46 |
+
try {
|
47 |
+
const filePath = file.path.toLowerCase().trim()
|
48 |
+
// TODO we should add some safety mechanisms here:
|
49 |
+
// skip lists of files that are too long
|
50 |
+
// skip files that are too big
|
51 |
+
// skip files with file.security.safe !== true
|
52 |
+
|
53 |
+
// console.log("file.path:", file.path)
|
54 |
+
/// { type, oid, size, path }
|
55 |
+
if (filePath === "readme.md") {
|
56 |
+
// console.log("found the README")
|
57 |
+
// TODO: read this readme
|
58 |
+
} else if (filePath.endsWith(".clap")) {
|
59 |
+
const clap = await downloadClapProject({
|
60 |
+
path: file.path,
|
61 |
+
channel,
|
62 |
+
apiKey
|
63 |
+
})
|
64 |
+
console.log("got a clap file:", clap.clapProject.meta)
|
65 |
+
|
66 |
+
// in the frontend UI we want to display everything,
|
67 |
+
// we don't filter stuff even if they are incomplete
|
68 |
+
|
69 |
+
videos[clap.videoRequest.id] = clap.videoRequest
|
70 |
+
} else if (filePath.startsWith("prompt_") && filePath.endsWith(".md")) {
|
71 |
+
|
72 |
+
const id = parsePromptFileName(filePath)
|
73 |
+
|
74 |
+
if (!id) { continue }
|
75 |
+
|
76 |
+
const rawMarkdown = await downloadFileAsText({
|
77 |
+
repo,
|
78 |
+
path: file.path, // be sure to use the original file.path (with capitalization if any) and not filePath
|
79 |
+
apiKey,
|
80 |
+
renewCache,
|
81 |
+
neverThrow: true,
|
82 |
+
})
|
83 |
+
|
84 |
+
if (!rawMarkdown) {
|
85 |
+
// console.log(`markdown file is empty, skipping`)
|
86 |
+
continue
|
87 |
+
}
|
88 |
+
|
89 |
+
const {
|
90 |
+
title,
|
91 |
+
description,
|
92 |
+
tags,
|
93 |
+
prompt,
|
94 |
+
thumbnail,
|
95 |
+
model,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
lora,
|
97 |
+
style,
|
98 |
+
music,
|
99 |
+
voice,
|
100 |
orientation,
|
101 |
+
} = parseDatasetPrompt(rawMarkdown, channel)
|
102 |
+
|
103 |
+
/*
|
104 |
+
on ai-tube side (not the ai-tube robot) we are okay with partial video requests,
|
105 |
+
ie. drafts
|
106 |
+
if (!title || !description || !prompt) {
|
107 |
+
// console.log("dataset prompt is incomplete or unparseable")
|
108 |
+
// continue
|
109 |
+
}
|
110 |
+
*/
|
111 |
+
|
112 |
+
// console.log("prompt parsed markdown:", { title, description, tags })
|
113 |
+
let thumbnailUrl =
|
114 |
+
thumbnail.startsWith("http")
|
115 |
+
? thumbnail
|
116 |
+
: (thumbnail.endsWith(".webp") || thumbnail.endsWith(".jpg") || thumbnail.endsWith(".jpeg"))
|
117 |
+
? `https://huggingface.co/${repo}/resolve/main/${thumbnail}`
|
118 |
+
: ""
|
119 |
+
|
120 |
+
// TODO: the clap file is empty if
|
121 |
+
// the video is prompted using Markdown
|
122 |
+
const clapUrl = ""
|
123 |
+
|
124 |
+
const video: VideoRequest = {
|
125 |
+
id,
|
126 |
+
label: title,
|
127 |
+
description,
|
128 |
+
prompt,
|
129 |
+
thumbnailUrl,
|
130 |
+
clapUrl,
|
131 |
+
model,
|
132 |
+
lora,
|
133 |
+
style,
|
134 |
+
voice,
|
135 |
+
music,
|
136 |
+
updatedAt: file.lastCommit?.date || new Date().toISOString(),
|
137 |
+
tags: Array.isArray(tags) && tags.length ? tags : channel.tags,
|
138 |
+
channel,
|
139 |
+
duration: 0,
|
140 |
+
...computeOrientationProjectionWidthHeight({
|
141 |
+
lora,
|
142 |
+
orientation,
|
143 |
+
// projection, // <- will be extrapolated from the LoRA for now
|
144 |
+
}),
|
145 |
+
}
|
146 |
+
|
147 |
+
videos[id] = video
|
148 |
+
|
149 |
+
} else if (filePath.endsWith(".mp4")) {
|
150 |
+
// console.log("found a video:", file.path)
|
151 |
}
|
152 |
+
} catch (err) {
|
153 |
+
console.error("error while processing a dataset file:")
|
154 |
+
console.error(err)
|
|
|
|
|
155 |
}
|
156 |
}
|
157 |
|
src/app/server/actions/ai-tube-hf/getVideos.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
"use server"
|
2 |
|
3 |
-
import { VideoInfo } from "@/types"
|
4 |
|
5 |
import { getVideoIndex } from "./getVideoIndex"
|
6 |
import { extendVideosWithStats } from "./extendVideosWithStats"
|
|
|
1 |
"use server"
|
2 |
|
3 |
+
import { VideoInfo } from "@/types/general"
|
4 |
|
5 |
import { getVideoIndex } from "./getVideoIndex"
|
6 |
import { extendVideosWithStats } from "./extendVideosWithStats"
|
src/app/server/actions/ai-tube-hf/parseChannel.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
import { Credentials, downloadFile, whoAmI } from "@/huggingface/hub/src"
|
4 |
import { parseDatasetReadme } from "@/app/server/actions/utils/parseDatasetReadme"
|
5 |
-
import { ChannelInfo, VideoGenerationModel, VideoOrientation } from "@/types"
|
6 |
|
7 |
import { adminCredentials } from "../config"
|
8 |
import { defaultVideoModel, defaultVideoOrientation } from "@/app/config"
|
|
|
2 |
|
3 |
import { Credentials, downloadFile, whoAmI } from "@/huggingface/hub/src"
|
4 |
import { parseDatasetReadme } from "@/app/server/actions/utils/parseDatasetReadme"
|
5 |
+
import { ChannelInfo, VideoGenerationModel, VideoOrientation } from "@/types/general"
|
6 |
|
7 |
import { adminCredentials } from "../config"
|
8 |
import { defaultVideoModel, defaultVideoOrientation } from "@/app/config"
|
src/app/server/actions/ai-tube-hf/uploadVideoRequestToDataset.ts
CHANGED
@@ -3,7 +3,7 @@
|
|
3 |
import { Blob } from "buffer"
|
4 |
|
5 |
import { Credentials, uploadFile, whoAmI } from "@/huggingface/hub/src"
|
6 |
-
import { ChannelInfo, VideoGenerationModel, VideoInfo, VideoOrientation, VideoRequest } from "@/types"
|
7 |
import { formatPromptFileName } from "../utils/formatPromptFileName"
|
8 |
import { computeOrientationProjectionWidthHeight } from "../utils/computeOrientationProjectionWidthHeight"
|
9 |
|
@@ -126,6 +126,10 @@ ${prompt}
|
|
126 |
voice,
|
127 |
music,
|
128 |
thumbnailUrl: channel.thumbnail,
|
|
|
|
|
|
|
|
|
129 |
updatedAt: new Date().toISOString(),
|
130 |
tags,
|
131 |
channel,
|
@@ -149,7 +153,12 @@ ${prompt}
|
|
149 |
voice,
|
150 |
music,
|
151 |
thumbnailUrl: channel.thumbnail, // will be generated in async
|
|
|
|
|
|
|
|
|
152 |
assetUrl: "", // will be generated in async
|
|
|
153 |
numberOfViews: 0,
|
154 |
numberOfLikes: 0,
|
155 |
numberOfDislikes: 0,
|
|
|
3 |
import { Blob } from "buffer"
|
4 |
|
5 |
import { Credentials, uploadFile, whoAmI } from "@/huggingface/hub/src"
|
6 |
+
import { ChannelInfo, VideoGenerationModel, VideoInfo, VideoOrientation, VideoRequest } from "@/types/general"
|
7 |
import { formatPromptFileName } from "../utils/formatPromptFileName"
|
8 |
import { computeOrientationProjectionWidthHeight } from "../utils/computeOrientationProjectionWidthHeight"
|
9 |
|
|
|
126 |
voice,
|
127 |
music,
|
128 |
thumbnailUrl: channel.thumbnail,
|
129 |
+
|
130 |
+
// for now AI Tube doesn't support upload of clap files
|
131 |
+
clapUrl: "",
|
132 |
+
|
133 |
updatedAt: new Date().toISOString(),
|
134 |
tags,
|
135 |
channel,
|
|
|
153 |
voice,
|
154 |
music,
|
155 |
thumbnailUrl: channel.thumbnail, // will be generated in async
|
156 |
+
|
157 |
+
// for now AI Tube doesn't support upload of clap files
|
158 |
+
clapUrl: "",
|
159 |
+
|
160 |
assetUrl: "", // will be generated in async
|
161 |
+
assetUrlHd: "",
|
162 |
numberOfViews: 0,
|
163 |
numberOfLikes: 0,
|
164 |
numberOfDislikes: 0,
|
src/app/server/actions/ai-tube-robot/updateQueue.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
"use server"
|
2 |
|
3 |
-
import { ChannelInfo, UpdateQueueResponse } from "@/types"
|
4 |
|
5 |
import { aiTubeRobotApi } from "../config"
|
6 |
|
|
|
1 |
"use server"
|
2 |
|
3 |
+
import { ChannelInfo, UpdateQueueResponse } from "@/types/general"
|
4 |
|
5 |
import { aiTubeRobotApi } from "../config"
|
6 |
|
src/app/server/actions/comments.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
import { v4 as uuidv4 } from "uuid"
|
4 |
|
5 |
-
import { CommentInfo, StoredCommentInfo } from "@/types"
|
6 |
import { stripHtml } from "@/lib/stripHtml"
|
7 |
import { getCurrentUser, getUsers } from "./users"
|
8 |
import { redis } from "./redis"
|
|
|
2 |
|
3 |
import { v4 as uuidv4 } from "uuid"
|
4 |
|
5 |
+
import { CommentInfo, StoredCommentInfo } from "@/types/general"
|
6 |
import { stripHtml } from "@/lib/stripHtml"
|
7 |
import { getCurrentUser, getUsers } from "./users"
|
8 |
import { redis } from "./redis"
|
src/app/server/actions/stats.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
import { developerMode } from "@/app/config"
|
4 |
import { WhoAmIUser, whoAmI } from "@/huggingface/hub/src"
|
5 |
-
import { VideoRating } from "@/types"
|
6 |
import { redis } from "./redis";
|
7 |
|
8 |
export async function getStatsForVideos(videoIds: string[]): Promise<Record<string, { numberOfViews: number; numberOfLikes: number; numberOfDislikes: number}>> {
|
|
|
2 |
|
3 |
import { developerMode } from "@/app/config"
|
4 |
import { WhoAmIUser, whoAmI } from "@/huggingface/hub/src"
|
5 |
+
import { VideoRating } from "@/types/general"
|
6 |
import { redis } from "./redis";
|
7 |
|
8 |
export async function getStatsForVideos(videoIds: string[]): Promise<Record<string, { numberOfViews: number; numberOfLikes: number; numberOfDislikes: number}>> {
|
src/app/server/actions/submitVideoRequest.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
"use server"
|
2 |
|
3 |
-
import { ChannelInfo, VideoGenerationModel, VideoInfo, VideoOrientation } from "@/types"
|
4 |
|
5 |
import { uploadVideoRequestToDataset } from "./ai-tube-hf/uploadVideoRequestToDataset"
|
6 |
|
|
|
1 |
"use server"
|
2 |
|
3 |
+
import { ChannelInfo, VideoGenerationModel, VideoInfo, VideoOrientation } from "@/types/general"
|
4 |
|
5 |
import { uploadVideoRequestToDataset } from "./ai-tube-hf/uploadVideoRequestToDataset"
|
6 |
|
src/app/server/actions/users.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
"use server"
|
2 |
|
3 |
import { WhoAmIUser, whoAmI } from "@/huggingface/hub/src"
|
4 |
-
import { UserInfo } from "@/types"
|
5 |
import { adminApiKey } from "./config"
|
6 |
import { redis } from "./redis"
|
7 |
|
|
|
1 |
"use server"
|
2 |
|
3 |
import { WhoAmIUser, whoAmI } from "@/huggingface/hub/src"
|
4 |
+
import { UserInfo } from "@/types/general"
|
5 |
import { adminApiKey } from "./config"
|
6 |
import { redis } from "./redis"
|
7 |
|
src/app/server/actions/utils/computeOrientationProjectionWidthHeight.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { VideoOrientation, VideoProjection } from "@/types"
|
2 |
|
3 |
import { parseVideoOrientation } from "./parseVideoOrientation"
|
4 |
import { parseProjectionFromLoRA } from "./parseProjectionFromLoRA"
|
|
|
1 |
+
import { VideoOrientation, VideoProjection } from "@/types/general"
|
2 |
|
3 |
import { parseVideoOrientation } from "./parseVideoOrientation"
|
4 |
import { parseProjectionFromLoRA } from "./parseProjectionFromLoRA"
|
src/app/server/actions/utils/isAntisocial.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { VideoInfo } from "@/types"
|
2 |
|
3 |
const winners = new Set(`${process.env.WINNERS || ""}`.toLowerCase().split(",").map(x => x.trim()).filter(x => x))
|
4 |
|
|
|
1 |
+
import { VideoInfo } from "@/types/general"
|
2 |
|
3 |
const winners = new Set(`${process.env.WINNERS || ""}`.toLowerCase().split(",").map(x => x.trim()).filter(x => x))
|
4 |
|
src/app/server/actions/utils/isHighQuality.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { VideoInfo } from "@/types"
|
2 |
|
3 |
export function isHighQuality(video: VideoInfo) {
|
4 |
const numberOfViews = Math.abs(Math.max(0, video.numberOfViews))
|
|
|
1 |
+
import { VideoInfo } from "@/types/general"
|
2 |
|
3 |
export function isHighQuality(video: VideoInfo) {
|
4 |
const numberOfViews = Math.abs(Math.max(0, video.numberOfViews))
|
src/app/server/actions/utils/parseClap.ts
ADDED
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import YAML from "yaml"
|
2 |
+
import { v4 as uuidv4 } from "uuid"
|
3 |
+
|
4 |
+
import { ClapHeader, ClapMeta, ClapProject, ClapSegment } from "@/types/clap"
|
5 |
+
import { getValidNumber } from "@/lib/getValidNumber"
|
6 |
+
|
7 |
+
/**
|
8 |
+
* import a Clap file (from a plain text string)
|
9 |
+
*
|
10 |
+
* note: it is not really async, because for some reason YAML.parse is a blocking call like for JSON,
|
11 |
+
* they is no async version although we are now in the 20s not 90s
|
12 |
+
*/
|
13 |
+
export async function parseClap(inputStringOrBlob: string | Blob): Promise<ClapProject> {
|
14 |
+
|
15 |
+
// Decompress the input blob using gzip
|
16 |
+
const decompressor = new DecompressionStream('gzip');
|
17 |
+
|
18 |
+
const inputBlob =
|
19 |
+
typeof inputStringOrBlob === "string"
|
20 |
+
? new Blob([inputStringOrBlob], { type: "application/x-yaml" })
|
21 |
+
: inputStringOrBlob;
|
22 |
+
|
23 |
+
const decompressedStream = inputBlob.stream().pipeThrough(decompressor);
|
24 |
+
|
25 |
+
// Convert the stream to text using a Response object
|
26 |
+
const text = await new Response(decompressedStream).text();
|
27 |
+
|
28 |
+
// Parse YAML string to raw data
|
29 |
+
const rawData = YAML.parse(text);
|
30 |
+
|
31 |
+
if (!Array.isArray(rawData) || rawData.length < 2) {
|
32 |
+
throw new Error("invalid clap file (need a clap format header block and project metadata block)")
|
33 |
+
}
|
34 |
+
|
35 |
+
const maybeClapHeader = rawData[0] as ClapHeader
|
36 |
+
|
37 |
+
if (maybeClapHeader.format !== "clap-0") {
|
38 |
+
throw new Error("invalid clap file (sorry, but you can't make up version numbers like that)")
|
39 |
+
}
|
40 |
+
|
41 |
+
const maybeClapMeta = rawData[1] as ClapMeta
|
42 |
+
|
43 |
+
const clapMeta: ClapMeta = {
|
44 |
+
id: typeof maybeClapMeta.title === "string" ? maybeClapMeta.id : uuidv4(),
|
45 |
+
title: typeof maybeClapMeta.title === "string" ? maybeClapMeta.title : "",
|
46 |
+
description: typeof maybeClapMeta.description === "string" ? maybeClapMeta.description : "",
|
47 |
+
licence: typeof maybeClapMeta.licence === "string" ? maybeClapMeta.licence : "",
|
48 |
+
orientation: maybeClapMeta.orientation === "portrait" ? "portrait" : maybeClapMeta.orientation === "square" ? "square" : "landscape",
|
49 |
+
width: getValidNumber(maybeClapMeta.width, 256, 4096, 1024),
|
50 |
+
height: getValidNumber(maybeClapMeta.height, 256, 4096, 1024),
|
51 |
+
defaultVideoModel: typeof maybeClapMeta.defaultVideoModel === "string" ? maybeClapMeta.defaultVideoModel : "SVD",
|
52 |
+
}
|
53 |
+
|
54 |
+
const maybeSegments = rawData.slice(2) as ClapSegment[]
|
55 |
+
|
56 |
+
const clapSegments: ClapSegment[] = Array.isArray(maybeSegments) ? maybeSegments.map(({
|
57 |
+
id,
|
58 |
+
track,
|
59 |
+
startTimeInMs,
|
60 |
+
endTimeInMs,
|
61 |
+
category,
|
62 |
+
modelId,
|
63 |
+
prompt,
|
64 |
+
outputType,
|
65 |
+
renderId,
|
66 |
+
status,
|
67 |
+
assetUrl,
|
68 |
+
outputGain,
|
69 |
+
seed,
|
70 |
+
}) => ({
|
71 |
+
// TODO: we should verify each of those, probably
|
72 |
+
id,
|
73 |
+
track,
|
74 |
+
startTimeInMs,
|
75 |
+
endTimeInMs,
|
76 |
+
category,
|
77 |
+
modelId,
|
78 |
+
prompt,
|
79 |
+
outputType,
|
80 |
+
renderId,
|
81 |
+
status,
|
82 |
+
assetUrl,
|
83 |
+
outputGain,
|
84 |
+
seed,
|
85 |
+
})) : []
|
86 |
+
|
87 |
+
return {
|
88 |
+
meta: clapMeta,
|
89 |
+
segments: clapSegments
|
90 |
+
}
|
91 |
+
}
|
src/app/server/actions/utils/parseDatasetPrompt.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
|
2 |
-
import { ChannelInfo, ParsedDatasetPrompt } from "@/types"
|
3 |
import { parseVideoModelName } from "./parseVideoModelName"
|
4 |
import { parseVideoOrientation } from "./parseVideoOrientation"
|
5 |
import { defaultVideoModel, defaultVideoOrientation } from "@/app/config"
|
|
|
1 |
|
2 |
+
import { ChannelInfo, ParsedDatasetPrompt } from "@/types/general"
|
3 |
import { parseVideoModelName } from "./parseVideoModelName"
|
4 |
import { parseVideoOrientation } from "./parseVideoOrientation"
|
5 |
import { defaultVideoModel, defaultVideoOrientation } from "@/app/config"
|