jbilcke-hf HF staff commited on
Commit
2f34958
Β·
1 Parent(s): 8f24b44
.env CHANGED
@@ -1,3 +1,3 @@
1
  NEXT_PUBLIC_BASE_URL=https://jbilcke-hf-videochain-ui.hf.space
2
- NEXT_PUBLIC_DOWNLOAD_URL=https://jbilcke-hf-videochain-api.hf.space/download
3
  VC_VIDEOCHAIN_API_URL=https://jbilcke-hf-videochain-api.hf.space
 
1
  NEXT_PUBLIC_BASE_URL=https://jbilcke-hf-videochain-ui.hf.space
2
+ NEXT_PUBLIC_DOWNLOAD_URL=https://jbilcke-hf-videochain-api.hf.space
3
  VC_VIDEOCHAIN_API_URL=https://jbilcke-hf-videochain-api.hf.space
src/app/studio/[ownerId]/main.tsx CHANGED
@@ -12,13 +12,13 @@ export default function Main({ videos }: { videos: Video[] }) {
12
  const [selectedVideo, selectVideo] = useState<Video>()
13
 
14
  return (
15
- <div className="flex flex-col md:flex-row">
16
- <div className="h-full flex flex-col space-y-4 w-full md:w-[800px] px-4 py-8">
17
  <VideoForm />
18
  <VideosQueue videos={videos} onSelectVideo={selectVideo} />
19
  <RefreshStudio />
20
  </div>
21
- <div className="flex flex-col w-auto">
22
  <VideoPlayer video={selectedVideo} />
23
  </div>
24
  </div>
 
12
  const [selectedVideo, selectVideo] = useState<Video>()
13
 
14
  return (
15
+ <div className="flex flex-col md:flex-row w-full">
16
+ <div className="h-full flex flex-col space-y-4 w-full md:w-1/2 px-4 py-8">
17
  <VideoForm />
18
  <VideosQueue videos={videos} onSelectVideo={selectVideo} />
19
  <RefreshStudio />
20
  </div>
21
+ <div className="flex flex-col w-1/2">
22
  <VideoPlayer video={selectedVideo} />
23
  </div>
24
  </div>
src/components/business/video-form.tsx CHANGED
@@ -17,27 +17,24 @@ export const VideoForm = () => {
17
  <form
18
  action={handleFormSubmit}
19
  >
20
- <div className="flex flex-col md:hidden w-full text-center">
21
- <h2 className="text-4xl font-thin tracking-tight">VideoChain UI</h2>
22
- <p className="text-md font-thin">
23
- Powered by <span className="font-normal">Hugging Face πŸ€—</span>
24
- </p>
25
- <p className="text-md font-thin">
26
- Keep the <a href={`/studio/${ownerId}`} className="font-normal" target="_blank">the link</a> to this page!
27
- </p>
28
- </div>
29
-
30
- <div className="flex items-center justify-between md:space-x-3 w-full">
31
- <div className="hidden md:flex flex-col w-54">
32
  <h2 className="text-4xl font-thin tracking-tight">VideoChain UI</h2>
33
  <p className="text-md font-thin">
34
  Powered by <span className="font-normal">Hugging Face πŸ€—</span>
35
  </p>
 
 
 
 
 
36
  <p className="text-md font-thin">
37
- Save <a href={`/studio/${ownerId}`} className="font-normal" target="_blank">the link</a> to your favorites!
38
  </p>
39
  </div>
 
40
 
 
41
  <input
42
  type="hidden"
43
  id="ownerId"
@@ -48,8 +45,8 @@ export const VideoForm = () => {
48
  <Textarea
49
  id="prompt"
50
  name="prompt"
51
- placeholder="Video of llamas playing baseball.."
52
- className="md:w-3/6 mr-3 md:mr-0"
53
  />
54
 
55
  <Button
 
17
  <form
18
  action={handleFormSubmit}
19
  >
20
+ <div className="flex flex-row w-full">
21
+ <div className="flex flex-col w-1/2 text-center">
 
 
 
 
 
 
 
 
 
 
22
  <h2 className="text-4xl font-thin tracking-tight">VideoChain UI</h2>
23
  <p className="text-md font-thin">
24
  Powered by <span className="font-normal">Hugging Face πŸ€—</span>
25
  </p>
26
+ </div>
27
+ <div className="flex flex-col w-1/2 text-center">
28
+ <p className="text-md font-thin">
29
+ This is an experimental Space, for research and demonstration purposes only.
30
+ </p>
31
  <p className="text-md font-thin">
32
+ This page has a unique URL, keep <a href={`/studio/${ownerId}`} className="font-normal" target="_blank">the link</a> to share videos!
33
  </p>
34
  </div>
35
+ </div>
36
 
37
+ <div className="flex items-center justify-between md:space-x-3 w-full">
38
  <input
39
  type="hidden"
40
  id="ownerId"
 
45
  <Textarea
46
  id="prompt"
47
  name="prompt"
48
+ placeholder="6 sec video of llamas playing soccer"
49
+ className="mr-3 md:mr-0"
50
  />
51
 
52
  <Button
src/components/business/video-player.tsx CHANGED
@@ -16,8 +16,10 @@ export const VideoPlayer = ({ video }: { video?: Video }) => {
16
  src={`${
17
  process.env.NEXT_PUBLIC_DOWNLOAD_URL
18
  }/${
19
- video.fileName
20
- }?progress=${
 
 
21
  video.progressPercent
22
  }`}
23
  muted
 
16
  src={`${
17
  process.env.NEXT_PUBLIC_DOWNLOAD_URL
18
  }/${
19
+ video.ownerId
20
+ }/${
21
+ video.id
22
+ }.mp4?progress=${
23
  video.progressPercent
24
  }`}
25
  muted
src/components/business/videos/columns.tsx CHANGED
@@ -8,6 +8,7 @@ import { VideoActions } from "./video-actions"
8
 
9
  import { Video } from "@/app/types"
10
  import { deleteVideo } from "@/server"
 
11
 
12
  export const columns: ColumnDef<Video>[] = [
13
  {
@@ -61,24 +62,18 @@ export const columns: ColumnDef<Video>[] = [
61
  enableSorting: false,
62
  },
63
  {
64
- accessorKey: "fileName",
65
  header: ({ column }) => null,// no header
66
  cell: ({ row: { original: { ownerId, id, progressPercent } } }) => <div className="w-[100px]">
67
- <a
68
- className="hover:underline cursor-pointer"
69
- target="_blank"
70
- href={`${process.env.NEXT_PUBLIC_DOWNLOAD_URL}/${ownerId}/${id}.mp4`}>
71
- <video src={`${process.env.NEXT_PUBLIC_DOWNLOAD_URL}/${ownerId}/${id}.mp4?progress=${progressPercent || 0}`} muted />
72
- </a>
73
  </div>,
74
  enableSorting: false,
75
  enableHiding: false,
76
  },
77
- /*
78
  {
79
- accessorKey: "fileName",
80
  header: ({ column }) => null,
81
- cell: ({ row: { original: { fileName, ownerId, id }} }) => <div className="">
82
  <a
83
  className="hover:underline cursor-pointer"
84
  target="_blank"
@@ -87,9 +82,36 @@ export const columns: ColumnDef<Video>[] = [
87
  enableSorting: false,
88
  enableHiding: false,
89
  },
90
- */
91
  {
92
- accessorKey: "delete",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  header: ({ column }) => null, // no header
94
  cell: ({ row: { original } }) => <div
95
  className="hover:underline cursor-pointer"
@@ -97,8 +119,10 @@ export const columns: ColumnDef<Video>[] = [
97
  enableSorting: false,
98
  enableHiding: false,
99
  },
 
100
  {
101
  id: "actions",
102
  cell: ({ row }) => <VideoActions row={row} />,
103
  },
 
104
  ]
 
8
 
9
  import { Video } from "@/app/types"
10
  import { deleteVideo } from "@/server"
11
+ import { triggerDownload } from "@/lib/triggerDownload"
12
 
13
  export const columns: ColumnDef<Video>[] = [
14
  {
 
62
  enableSorting: false,
63
  },
64
  {
65
+ id: "preview",
66
  header: ({ column }) => null,// no header
67
  cell: ({ row: { original: { ownerId, id, progressPercent } } }) => <div className="w-[100px]">
68
+ <video src={`${process.env.NEXT_PUBLIC_DOWNLOAD_URL}/${ownerId}/${id}.mp4?progress=${progressPercent || 0}`} muted />
 
 
 
 
 
69
  </div>,
70
  enableSorting: false,
71
  enableHiding: false,
72
  },
 
73
  {
74
+ id: "save",
75
  header: ({ column }) => null,
76
+ cell: ({ row: { original: { ownerId, id }} }) => <div className="">
77
  <a
78
  className="hover:underline cursor-pointer"
79
  target="_blank"
 
82
  enableSorting: false,
83
  enableHiding: false,
84
  },
 
85
  {
86
+ id: "save",
87
+ header: ({ column }) => null,
88
+ cell: ({ row: { original } }) => {
89
+ const scene = JSON.stringify({
90
+ videoPrompt: original.videoPrompt,
91
+ backgroundAudioPrompt: original.backgroundAudioPrompt,
92
+ foregroundAudioPrompt: original.foregroundAudioPrompt,
93
+ shots: original.shots.map(shot => ({
94
+ shotPrompt: shot.shotPrompt,
95
+ backgroundAudioPrompt: shot.backgroundAudioPrompt,
96
+ foregroundAudioPrompt: shot.foregroundAudioPrompt,
97
+ actorPrompt: shot.actorPrompt,
98
+ actorVoicePrompt: shot.actorVoicePrompt,
99
+ actorDialoguePrompt: shot.actorDialoguePrompt,
100
+ }))
101
+ }, null, 2)
102
+ return (<div className="">
103
+ <a
104
+ className="hover:underline cursor-pointer"
105
+ target="_blank"
106
+ onClick={() => triggerDownload("scene.json", scene)}>Scene</a>
107
+ </div>
108
+ )
109
+ },
110
+ enableSorting: false,
111
+ enableHiding: false,
112
+ },
113
+ {
114
+ id: "delete",
115
  header: ({ column }) => null, // no header
116
  cell: ({ row: { original } }) => <div
117
  className="hover:underline cursor-pointer"
 
119
  enableSorting: false,
120
  enableHiding: false,
121
  },
122
+ /*
123
  {
124
  id: "actions",
125
  cell: ({ row }) => <VideoActions row={row} />,
126
  },
127
+ */
128
  ]
src/components/business/videos/video-actions.tsx CHANGED
@@ -34,10 +34,12 @@ export function VideoActions({
34
  </Button>
35
  </DropdownMenuTrigger>
36
  <DropdownMenuContent align="end" className="w-[160px]">
37
- <DropdownMenuItem>
 
38
  Pause generation
39
  <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
40
  </DropdownMenuItem>
 
41
  <DropdownMenuItem>Download</DropdownMenuItem>
42
  <DropdownMenuSeparator />
43
  <DropdownMenuItem>
 
34
  </Button>
35
  </DropdownMenuTrigger>
36
  <DropdownMenuContent align="end" className="w-[160px]">
37
+ {/*
38
+ <DropdownMenuItem>
39
  Pause generation
40
  <DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
41
  </DropdownMenuItem>
42
+ */}
43
  <DropdownMenuItem>Download</DropdownMenuItem>
44
  <DropdownMenuSeparator />
45
  <DropdownMenuItem>
src/lib/triggerDownload.ts ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function triggerDownload(filename: string, text: string) {
2
+ var element = document.createElement('a');
3
+ element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
4
+ element.setAttribute('download', filename);
5
+
6
+ element.style.display = 'none';
7
+ document.body.appendChild(element);
8
+
9
+ element.click();
10
+
11
+ document.body.removeChild(element);
12
+ }