Commit
•
846ea5b
1
Parent(s):
989fb3a
project is starting to take shape
Browse files- package-lock.json +26 -17
- package.json +2 -1
- src/app/main.tsx +6 -6
- src/app/server/aitube/config.ts +0 -3
- src/app/server/aitube/{generateClap.ts → createClap.ts} +11 -4
- src/app/server/aitube/editClapStoryboards.ts +19 -0
- src/app/server/aitube/exportClap.ts +0 -12
- src/app/server/aitube/exportClapToVideo.ts +23 -0
- src/app/server/aitube/extendClap.ts +0 -12
- src/app/server/aitube/getToken.ts +20 -0
package-lock.json
CHANGED
@@ -9,7 +9,7 @@
|
|
9 |
"version": "0.0.0",
|
10 |
"dependencies": {
|
11 |
"@aitube/clap": "^0.0.6",
|
12 |
-
"@aitube/client": "^0.0.
|
13 |
"@radix-ui/react-accordion": "^1.1.2",
|
14 |
"@radix-ui/react-avatar": "^1.0.4",
|
15 |
"@radix-ui/react-checkbox": "^1.0.4",
|
@@ -39,6 +39,7 @@
|
|
39 |
"eslint": "8.56.0",
|
40 |
"eslint-config-next": "14.1.0",
|
41 |
"jimp": "^0.22.12",
|
|
|
42 |
"lucide-react": "^0.334.0",
|
43 |
"next": "^14.2.3",
|
44 |
"next-themes": "^0.2.1",
|
@@ -60,14 +61,6 @@
|
|
60 |
"zustand": "^4.5.2"
|
61 |
}
|
62 |
},
|
63 |
-
"node_modules/@aashutoshrathi/word-wrap": {
|
64 |
-
"version": "1.2.6",
|
65 |
-
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
|
66 |
-
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
|
67 |
-
"engines": {
|
68 |
-
"node": ">=0.10.0"
|
69 |
-
}
|
70 |
-
},
|
71 |
"node_modules/@aitube/clap": {
|
72 |
"version": "0.0.6",
|
73 |
"resolved": "https://registry.npmjs.org/@aitube/clap/-/clap-0.0.6.tgz",
|
@@ -81,9 +74,9 @@
|
|
81 |
}
|
82 |
},
|
83 |
"node_modules/@aitube/client": {
|
84 |
-
"version": "0.0.
|
85 |
-
"resolved": "https://registry.npmjs.org/@aitube/client/-/client-0.0.
|
86 |
-
"integrity": "sha512-
|
87 |
"dependencies": {
|
88 |
"uuid": "^9.0.1",
|
89 |
"yaml": "^2.4.1"
|
@@ -5315,6 +5308,14 @@
|
|
5315 |
"jiti": "bin/jiti.js"
|
5316 |
}
|
5317 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5318 |
"node_modules/jpeg-js": {
|
5319 |
"version": "0.4.4",
|
5320 |
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
|
@@ -5863,16 +5864,16 @@
|
|
5863 |
}
|
5864 |
},
|
5865 |
"node_modules/optionator": {
|
5866 |
-
"version": "0.9.
|
5867 |
-
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.
|
5868 |
-
"integrity": "sha512-
|
5869 |
"dependencies": {
|
5870 |
-
"@aashutoshrathi/word-wrap": "^1.2.3",
|
5871 |
"deep-is": "^0.1.3",
|
5872 |
"fast-levenshtein": "^2.0.6",
|
5873 |
"levn": "^0.4.1",
|
5874 |
"prelude-ls": "^1.2.1",
|
5875 |
-
"type-check": "^0.4.0"
|
|
|
5876 |
},
|
5877 |
"engines": {
|
5878 |
"node": ">= 0.8.0"
|
@@ -7665,6 +7666,14 @@
|
|
7665 |
"url": "https://github.com/sponsors/ljharb"
|
7666 |
}
|
7667 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7668 |
"node_modules/wrap-ansi": {
|
7669 |
"version": "8.1.0",
|
7670 |
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
|
|
9 |
"version": "0.0.0",
|
10 |
"dependencies": {
|
11 |
"@aitube/clap": "^0.0.6",
|
12 |
+
"@aitube/client": "^0.0.4",
|
13 |
"@radix-ui/react-accordion": "^1.1.2",
|
14 |
"@radix-ui/react-avatar": "^1.0.4",
|
15 |
"@radix-ui/react-checkbox": "^1.0.4",
|
|
|
39 |
"eslint": "8.56.0",
|
40 |
"eslint-config-next": "14.1.0",
|
41 |
"jimp": "^0.22.12",
|
42 |
+
"jose": "^5.2.4",
|
43 |
"lucide-react": "^0.334.0",
|
44 |
"next": "^14.2.3",
|
45 |
"next-themes": "^0.2.1",
|
|
|
61 |
"zustand": "^4.5.2"
|
62 |
}
|
63 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
"node_modules/@aitube/clap": {
|
65 |
"version": "0.0.6",
|
66 |
"resolved": "https://registry.npmjs.org/@aitube/clap/-/clap-0.0.6.tgz",
|
|
|
74 |
}
|
75 |
},
|
76 |
"node_modules/@aitube/client": {
|
77 |
+
"version": "0.0.4",
|
78 |
+
"resolved": "https://registry.npmjs.org/@aitube/client/-/client-0.0.4.tgz",
|
79 |
+
"integrity": "sha512-LzOYgwSKJVslGbTEP3DEsgh5/EWupv04HNoTt3hxDQBo9/I5AF/ZwoLBDQR3QTu1i3spMJ61Sl0gVtrXxp2q3A==",
|
80 |
"dependencies": {
|
81 |
"uuid": "^9.0.1",
|
82 |
"yaml": "^2.4.1"
|
|
|
5308 |
"jiti": "bin/jiti.js"
|
5309 |
}
|
5310 |
},
|
5311 |
+
"node_modules/jose": {
|
5312 |
+
"version": "5.2.4",
|
5313 |
+
"resolved": "https://registry.npmjs.org/jose/-/jose-5.2.4.tgz",
|
5314 |
+
"integrity": "sha512-6ScbIk2WWCeXkmzF6bRPmEuaqy1m8SbsRFMa/FLrSCkGIhj8OLVG/IH+XHVmNMx/KUo8cVWEE6oKR4dJ+S0Rkg==",
|
5315 |
+
"funding": {
|
5316 |
+
"url": "https://github.com/sponsors/panva"
|
5317 |
+
}
|
5318 |
+
},
|
5319 |
"node_modules/jpeg-js": {
|
5320 |
"version": "0.4.4",
|
5321 |
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
|
|
|
5864 |
}
|
5865 |
},
|
5866 |
"node_modules/optionator": {
|
5867 |
+
"version": "0.9.4",
|
5868 |
+
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
5869 |
+
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
|
5870 |
"dependencies": {
|
|
|
5871 |
"deep-is": "^0.1.3",
|
5872 |
"fast-levenshtein": "^2.0.6",
|
5873 |
"levn": "^0.4.1",
|
5874 |
"prelude-ls": "^1.2.1",
|
5875 |
+
"type-check": "^0.4.0",
|
5876 |
+
"word-wrap": "^1.2.5"
|
5877 |
},
|
5878 |
"engines": {
|
5879 |
"node": ">= 0.8.0"
|
|
|
7666 |
"url": "https://github.com/sponsors/ljharb"
|
7667 |
}
|
7668 |
},
|
7669 |
+
"node_modules/word-wrap": {
|
7670 |
+
"version": "1.2.5",
|
7671 |
+
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
7672 |
+
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
7673 |
+
"engines": {
|
7674 |
+
"node": ">=0.10.0"
|
7675 |
+
}
|
7676 |
+
},
|
7677 |
"node_modules/wrap-ansi": {
|
7678 |
"version": "8.1.0",
|
7679 |
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
|
package.json
CHANGED
@@ -10,7 +10,7 @@
|
|
10 |
},
|
11 |
"dependencies": {
|
12 |
"@aitube/clap": "^0.0.6",
|
13 |
-
"@aitube/client": "^0.0.
|
14 |
"@radix-ui/react-accordion": "^1.1.2",
|
15 |
"@radix-ui/react-avatar": "^1.0.4",
|
16 |
"@radix-ui/react-checkbox": "^1.0.4",
|
@@ -40,6 +40,7 @@
|
|
40 |
"eslint": "8.56.0",
|
41 |
"eslint-config-next": "14.1.0",
|
42 |
"jimp": "^0.22.12",
|
|
|
43 |
"lucide-react": "^0.334.0",
|
44 |
"next": "^14.2.3",
|
45 |
"next-themes": "^0.2.1",
|
|
|
10 |
},
|
11 |
"dependencies": {
|
12 |
"@aitube/clap": "^0.0.6",
|
13 |
+
"@aitube/client": "^0.0.4",
|
14 |
"@radix-ui/react-accordion": "^1.1.2",
|
15 |
"@radix-ui/react-avatar": "^1.0.4",
|
16 |
"@radix-ui/react-checkbox": "^1.0.4",
|
|
|
40 |
"eslint": "8.56.0",
|
41 |
"eslint-config-next": "14.1.0",
|
42 |
"jimp": "^0.22.12",
|
43 |
+
"jose": "^5.2.4",
|
44 |
"lucide-react": "^0.334.0",
|
45 |
"next": "^14.2.3",
|
46 |
"next-themes": "^0.2.1",
|
src/app/main.tsx
CHANGED
@@ -12,9 +12,9 @@ import { useStore } from './store'
|
|
12 |
import { TextareaField } from '@/components/form/textarea-field'
|
13 |
import { DeviceFrameset } from 'react-device-frameset'
|
14 |
import 'react-device-frameset/styles/marvel-devices.min.css'
|
15 |
-
import {
|
16 |
-
import {
|
17 |
-
import {
|
18 |
|
19 |
export function Main() {
|
20 |
const [_isPending, startTransition] = useTransition()
|
@@ -53,7 +53,7 @@ export function Main() {
|
|
53 |
|
54 |
let clap: ClapProject | undefined = undefined
|
55 |
try {
|
56 |
-
clap = await
|
57 |
|
58 |
console.log(`handleSubmit(): received a clap = `, clap)
|
59 |
setStoryGenerationStatus("finished")
|
@@ -68,7 +68,7 @@ export function Main() {
|
|
68 |
|
69 |
try {
|
70 |
setImageGenerationStatus("generating")
|
71 |
-
clap = await
|
72 |
|
73 |
console.log(`handleSubmit(): received a clap with images = `, clap)
|
74 |
setImageGenerationStatus("finished")
|
@@ -84,7 +84,7 @@ export function Main() {
|
|
84 |
let assetUrl = ""
|
85 |
try {
|
86 |
setVideoGenerationStatus("generating")
|
87 |
-
assetUrl = await
|
88 |
|
89 |
console.log(`handleSubmit(): received a video:`, assetUrl)
|
90 |
setVideoGenerationStatus("finished")
|
|
|
12 |
import { TextareaField } from '@/components/form/textarea-field'
|
13 |
import { DeviceFrameset } from 'react-device-frameset'
|
14 |
import 'react-device-frameset/styles/marvel-devices.min.css'
|
15 |
+
import { createClap } from './server/aitube/createClap'
|
16 |
+
import { editClapStoryboards } from './server/aitube/editClapStoryboards'
|
17 |
+
import { exportClapToVideo } from './server/aitube/exportClapToVideo'
|
18 |
|
19 |
export function Main() {
|
20 |
const [_isPending, startTransition] = useTransition()
|
|
|
53 |
|
54 |
let clap: ClapProject | undefined = undefined
|
55 |
try {
|
56 |
+
clap = await createClap({ prompt })
|
57 |
|
58 |
console.log(`handleSubmit(): received a clap = `, clap)
|
59 |
setStoryGenerationStatus("finished")
|
|
|
68 |
|
69 |
try {
|
70 |
setImageGenerationStatus("generating")
|
71 |
+
clap = await editClapStoryboards({ clap })
|
72 |
|
73 |
console.log(`handleSubmit(): received a clap with images = `, clap)
|
74 |
setImageGenerationStatus("finished")
|
|
|
84 |
let assetUrl = ""
|
85 |
try {
|
86 |
setVideoGenerationStatus("generating")
|
87 |
+
assetUrl = await exportClapToVideo({ clap })
|
88 |
|
89 |
console.log(`handleSubmit(): received a video:`, assetUrl)
|
90 |
setVideoGenerationStatus("finished")
|
src/app/server/aitube/config.ts
CHANGED
@@ -1,5 +1,2 @@
|
|
1 |
|
2 |
export const serverHuggingfaceApiKey = `${process.env.HF_API_TOKEN || ""}`
|
3 |
-
|
4 |
-
export const aitubeUrl = `${process.env.AI_TUBE_URL || "" }`
|
5 |
-
export const aitubeApiUrl = aitubeUrl + (aitubeUrl.endsWith("/") ? "" : "/") + "api/"
|
|
|
1 |
|
2 |
export const serverHuggingfaceApiKey = `${process.env.HF_API_TOKEN || ""}`
|
|
|
|
|
|
src/app/server/aitube/{generateClap.ts → createClap.ts}
RENAMED
@@ -1,12 +1,19 @@
|
|
1 |
"use server"
|
2 |
|
3 |
import { ClapProject } from "@aitube/clap"
|
4 |
-
import
|
5 |
|
6 |
-
|
|
|
|
|
7 |
prompt = "",
|
8 |
}: {
|
9 |
prompt: string
|
10 |
}): Promise<ClapProject> {
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
1 |
"use server"
|
2 |
|
3 |
import { ClapProject } from "@aitube/clap"
|
4 |
+
import { createClap as apiCreateClap } from "@aitube/client"
|
5 |
|
6 |
+
import { getToken } from "./getToken"
|
7 |
+
|
8 |
+
export async function createClap({
|
9 |
prompt = "",
|
10 |
}: {
|
11 |
prompt: string
|
12 |
}): Promise<ClapProject> {
|
13 |
+
const clap: ClapProject = await apiCreateClap({
|
14 |
+
prompt,
|
15 |
+
token: await getToken()
|
16 |
+
})
|
17 |
+
|
18 |
+
return clap
|
19 |
+
}
|
src/app/server/aitube/editClapStoryboards.ts
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use server"
|
2 |
+
|
3 |
+
import { ClapProject } from "@aitube/clap"
|
4 |
+
import { editClapStoryboards as apiEditClapStoryboards } from "@aitube/client"
|
5 |
+
|
6 |
+
import { getToken } from "./getToken"
|
7 |
+
|
8 |
+
export async function editClapStoryboards({
|
9 |
+
clap,
|
10 |
+
}: {
|
11 |
+
clap: ClapProject
|
12 |
+
}): Promise<ClapProject> {
|
13 |
+
const newClap: ClapProject = await apiEditClapStoryboards({
|
14 |
+
clap,
|
15 |
+
token: await getToken()
|
16 |
+
})
|
17 |
+
|
18 |
+
return newClap
|
19 |
+
}
|
src/app/server/aitube/exportClap.ts
DELETED
@@ -1,12 +0,0 @@
|
|
1 |
-
"use server"
|
2 |
-
|
3 |
-
import { ClapProject } from "@aitube/clap"
|
4 |
-
import * as aitube from "@aitube/client"
|
5 |
-
|
6 |
-
export async function exportClap({
|
7 |
-
clap,
|
8 |
-
}: {
|
9 |
-
clap: ClapProject
|
10 |
-
}): Promise<string> {
|
11 |
-
return aitube.exportClap({ clap })
|
12 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app/server/aitube/exportClapToVideo.ts
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"use server"
|
2 |
+
|
3 |
+
import { ClapProject } from "@aitube/clap"
|
4 |
+
import { exportClapToVideo as apiExportClapToVideo } from "@aitube/client"
|
5 |
+
|
6 |
+
import { getToken } from "./getToken"
|
7 |
+
|
8 |
+
export async function exportClapToVideo({
|
9 |
+
clap,
|
10 |
+
}: {
|
11 |
+
clap: ClapProject
|
12 |
+
}): Promise<string> {
|
13 |
+
// TODO: maybe we should return a blob instead,
|
14 |
+
// as this could be big eg. a few megabytes
|
15 |
+
// or maybe we should convert it to an object id
|
16 |
+
const dataUri: string = await apiExportClapToVideo({
|
17 |
+
clap,
|
18 |
+
format: "mp4",
|
19 |
+
token: await getToken()
|
20 |
+
})
|
21 |
+
|
22 |
+
return dataUri
|
23 |
+
}
|
src/app/server/aitube/extendClap.ts
DELETED
@@ -1,12 +0,0 @@
|
|
1 |
-
"use server"
|
2 |
-
|
3 |
-
import { ClapProject } from "@aitube/clap"
|
4 |
-
import * as aitube from "@aitube/client"
|
5 |
-
|
6 |
-
export async function extendClap({
|
7 |
-
clap,
|
8 |
-
}: {
|
9 |
-
clap: ClapProject
|
10 |
-
}): Promise<ClapProject> {
|
11 |
-
return aitube.extendClap({ clap })
|
12 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app/server/aitube/getToken.ts
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { createSecretKey } from "crypto"
|
2 |
+
import { SignJWT } from "jose"
|
3 |
+
|
4 |
+
// https://jmswrnr.com/blog/protecting-next-js-api-routes-query-parameters
|
5 |
+
|
6 |
+
export async function getToken(data: Record<string, any> = {}): Promise<string> {
|
7 |
+
const secretKey = createSecretKey(`${process.env.AI_TUBE_API_SECRET_JWT_KEY || ""}`, 'utf-8');
|
8 |
+
|
9 |
+
const jwtToken = await new SignJWT(data)
|
10 |
+
.setProtectedHeader({
|
11 |
+
alg: 'HS256'
|
12 |
+
}) // algorithm
|
13 |
+
.setIssuedAt()
|
14 |
+
.setIssuer(`${process.env.AI_TUBE_API_SECRET_JWT_ISSUER || ""}`) // issuer
|
15 |
+
.setAudience(`${process.env.AI_TUBE_API_SECRET_JWT_AUDIENCE || ""}`) // audience
|
16 |
+
.setExpirationTime("1 day") // token expiration time - to prevent hackers from re-using our URLs more than a day
|
17 |
+
.sign(secretKey); // secretKey generated from previous step
|
18 |
+
|
19 |
+
return jwtToken
|
20 |
+
}
|