Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
Commit
•
03a79fc
1
Parent(s):
4e412a8
fix issues
Browse files- packages/client/.gitignore +177 -0
- packages/client/.npmignore +4 -0
- packages/client/.prettierrc.json +9 -0
- packages/client/LICENSE.md +21 -0
- packages/client/README.md +113 -0
- packages/client/package.json +46 -0
- packages/client/src/api/createClap.ts +43 -0
- packages/client/src/api/editClapDialogues.ts +61 -0
- packages/client/src/api/editClapEntities.ts +75 -0
- packages/client/src/api/editClapMusic.ts +60 -0
- packages/client/src/api/editClapSounds.ts +60 -0
- packages/client/src/api/editClapStory.ts +114 -0
- packages/client/src/api/editClapStoryboards.ts +60 -0
- packages/client/src/api/editClapVideos.ts +85 -0
- packages/client/src/api/exportClapToVideo.ts +60 -0
- packages/client/src/api/index.ts +9 -0
- packages/client/src/constants/config.ts +16 -0
- packages/client/src/constants/defaultValues.ts +10 -0
- packages/client/src/constants/index.ts +17 -0
- packages/client/src/constants/types.ts +25 -0
- packages/client/src/index.ts +28 -0
- packages/client/src/parsers/index.ts +3 -0
- packages/client/src/parsers/parseEntityPrompt.ts +30 -0
- packages/client/src/parsers/parseString.ts +7 -0
- packages/client/src/parsers/parseStringArray.ts +9 -0
- packages/client/src/utils/applyClapCompletion.ts +21 -0
- packages/client/src/utils/index.ts +1 -0
- packages/client/tsconfig.json +31 -0
- packages/client/tsconfig.types.json +13 -0
packages/client/.gitignore
ADDED
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
2 |
+
|
3 |
+
# Logs
|
4 |
+
|
5 |
+
logs
|
6 |
+
_.log
|
7 |
+
npm-debug.log_
|
8 |
+
yarn-debug.log*
|
9 |
+
yarn-error.log*
|
10 |
+
lerna-debug.log*
|
11 |
+
.pnpm-debug.log*
|
12 |
+
|
13 |
+
# Diagnostic reports (https://nodejs.org/api/report.html)
|
14 |
+
|
15 |
+
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
16 |
+
|
17 |
+
# Runtime data
|
18 |
+
|
19 |
+
pids
|
20 |
+
_.pid
|
21 |
+
_.seed
|
22 |
+
\*.pid.lock
|
23 |
+
|
24 |
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
25 |
+
|
26 |
+
lib-cov
|
27 |
+
|
28 |
+
# Coverage directory used by tools like istanbul
|
29 |
+
|
30 |
+
coverage
|
31 |
+
\*.lcov
|
32 |
+
|
33 |
+
# nyc test coverage
|
34 |
+
|
35 |
+
.nyc_output
|
36 |
+
|
37 |
+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
38 |
+
|
39 |
+
.grunt
|
40 |
+
|
41 |
+
# Bower dependency directory (https://bower.io/)
|
42 |
+
|
43 |
+
bower_components
|
44 |
+
|
45 |
+
# node-waf configuration
|
46 |
+
|
47 |
+
.lock-wscript
|
48 |
+
|
49 |
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
50 |
+
|
51 |
+
build/Release
|
52 |
+
|
53 |
+
# Dependency directories
|
54 |
+
|
55 |
+
node_modules/
|
56 |
+
jspm_packages/
|
57 |
+
|
58 |
+
# Snowpack dependency directory (https://snowpack.dev/)
|
59 |
+
|
60 |
+
web_modules/
|
61 |
+
|
62 |
+
# TypeScript cache
|
63 |
+
|
64 |
+
\*.tsbuildinfo
|
65 |
+
|
66 |
+
# Optional npm cache directory
|
67 |
+
|
68 |
+
.npm
|
69 |
+
|
70 |
+
# Optional eslint cache
|
71 |
+
|
72 |
+
.eslintcache
|
73 |
+
|
74 |
+
# Optional stylelint cache
|
75 |
+
|
76 |
+
.stylelintcache
|
77 |
+
|
78 |
+
# Microbundle cache
|
79 |
+
|
80 |
+
.rpt2_cache/
|
81 |
+
.rts2_cache_cjs/
|
82 |
+
.rts2_cache_es/
|
83 |
+
.rts2_cache_umd/
|
84 |
+
|
85 |
+
# Optional REPL history
|
86 |
+
|
87 |
+
.node_repl_history
|
88 |
+
|
89 |
+
# Output of 'npm pack'
|
90 |
+
|
91 |
+
\*.tgz
|
92 |
+
|
93 |
+
# Yarn Integrity file
|
94 |
+
|
95 |
+
.yarn-integrity
|
96 |
+
|
97 |
+
# dotenv environment variable files
|
98 |
+
|
99 |
+
.env
|
100 |
+
.env.development.local
|
101 |
+
.env.test.local
|
102 |
+
.env.production.local
|
103 |
+
.env.local
|
104 |
+
|
105 |
+
# parcel-bundler cache (https://parceljs.org/)
|
106 |
+
|
107 |
+
.cache
|
108 |
+
.parcel-cache
|
109 |
+
|
110 |
+
# Next.js build output
|
111 |
+
|
112 |
+
.next
|
113 |
+
out
|
114 |
+
|
115 |
+
# Nuxt.js build / generate output
|
116 |
+
dist
|
117 |
+
.nuxt
|
118 |
+
|
119 |
+
# Gatsby files
|
120 |
+
|
121 |
+
.cache/
|
122 |
+
|
123 |
+
# Comment in the public line in if your project uses Gatsby and not Next.js
|
124 |
+
|
125 |
+
# https://nextjs.org/blog/next-9-1#public-directory-support
|
126 |
+
|
127 |
+
# public
|
128 |
+
|
129 |
+
# vuepress build output
|
130 |
+
|
131 |
+
.vuepress/dist
|
132 |
+
|
133 |
+
# vuepress v2.x temp and cache directory
|
134 |
+
|
135 |
+
.temp
|
136 |
+
.cache
|
137 |
+
|
138 |
+
# Docusaurus cache and generated files
|
139 |
+
|
140 |
+
.docusaurus
|
141 |
+
|
142 |
+
# Serverless directories
|
143 |
+
|
144 |
+
.serverless/
|
145 |
+
|
146 |
+
# FuseBox cache
|
147 |
+
|
148 |
+
.fusebox/
|
149 |
+
|
150 |
+
# DynamoDB Local files
|
151 |
+
|
152 |
+
.dynamodb/
|
153 |
+
|
154 |
+
# TernJS port file
|
155 |
+
|
156 |
+
.tern-port
|
157 |
+
|
158 |
+
# Stores VSCode versions used for testing VSCode extensions
|
159 |
+
|
160 |
+
.vscode-test
|
161 |
+
|
162 |
+
# yarn v2
|
163 |
+
|
164 |
+
.yarn/cache
|
165 |
+
.yarn/unplugged
|
166 |
+
.yarn/build-state.yml
|
167 |
+
.yarn/install-state.gz
|
168 |
+
.pnp.\*
|
169 |
+
|
170 |
+
# IntelliJ based IDEs
|
171 |
+
.idea
|
172 |
+
|
173 |
+
# Finder (MacOS) folder config
|
174 |
+
.DS_Store
|
175 |
+
|
176 |
+
# TypeScript build information
|
177 |
+
*.tsbuildinfo
|
packages/client/.npmignore
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ignore everything
|
2 |
+
*
|
3 |
+
# Except the dist directory
|
4 |
+
!dist/
|
packages/client/.prettierrc.json
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"semi": false,
|
3 |
+
"singleQuote": true,
|
4 |
+
"arrowParens": "avoid",
|
5 |
+
"printWidth": 140,
|
6 |
+
"tabWidth": 2,
|
7 |
+
"trailingComma": "es5",
|
8 |
+
"bracketSpacing": true
|
9 |
+
}
|
packages/client/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2024 Julian Bilcke
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
packages/client/README.md
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# @aitube/client
|
2 |
+
|
3 |
+
*Official API client for AiTube.at*
|
4 |
+
|
5 |
+
## ATTENTION
|
6 |
+
|
7 |
+
AiTube is currently in heavy development, and for the moment
|
8 |
+
the API client is reserved for *private use* (it is used by AI Stories Factory).
|
9 |
+
|
10 |
+
We are sorry for any inconvenience this might cause.
|
11 |
+
|
12 |
+
## Caveats
|
13 |
+
|
14 |
+
The official domain for AiTube is `aitube.at`, however right now
|
15 |
+
the Hugging Face Space is not configured to use this as a domain,
|
16 |
+
so we need to perform all API calls to `jbilcke-hf-ai-tube.hf.space`.
|
17 |
+
|
18 |
+
## Installation
|
19 |
+
|
20 |
+
To install the package, run the following command:
|
21 |
+
|
22 |
+
```bash
|
23 |
+
npm install @aitube/client
|
24 |
+
```
|
25 |
+
|
26 |
+
## Getting Started
|
27 |
+
|
28 |
+
Note: to overridethe AiTube API URL, set this env var: `AITUBE_URL`
|
29 |
+
|
30 |
+
```typescript
|
31 |
+
import {
|
32 |
+
createClap,
|
33 |
+
editClapDialogues,
|
34 |
+
editClapEntities,
|
35 |
+
editClapMusic,
|
36 |
+
editClapSounds,
|
37 |
+
editClapStory,
|
38 |
+
editClapStoryboards,
|
39 |
+
editClapVideos,
|
40 |
+
exportClapToVideo,
|
41 |
+
defaultAitubeHostname,
|
42 |
+
defaultClapWidth,
|
43 |
+
defaultClapHeight,
|
44 |
+
defaultExportFormat,
|
45 |
+
aitubeUrl,
|
46 |
+
aitubeApiVersion,
|
47 |
+
aitubeApiUrl,
|
48 |
+
ClapEntityPrompt,
|
49 |
+
SupportedExportFormat,
|
50 |
+
applyClapCompletion,
|
51 |
+
} from '@aitube/client'
|
52 |
+
|
53 |
+
const ultraSecret = "ultra secret token unavailable to common mortals"
|
54 |
+
|
55 |
+
const basicClap = await createClap({
|
56 |
+
prompt: "story about a dog",
|
57 |
+
turbo: false,
|
58 |
+
token: ultraSecret
|
59 |
+
})
|
60 |
+
|
61 |
+
const illustratedClap = await editClapStoryboards({
|
62 |
+
clap: basicClap,
|
63 |
+
turbo: false,
|
64 |
+
token: ultraSecret
|
65 |
+
})
|
66 |
+
|
67 |
+
const mp4VideoFile = await exportClapToVideo({
|
68 |
+
clap: illustratedClap,
|
69 |
+
format: "mp4",
|
70 |
+
turbo: false,
|
71 |
+
token: ultraSecret
|
72 |
+
})
|
73 |
+
```
|
74 |
+
|
75 |
+
## Customizing the server
|
76 |
+
|
77 |
+
The hostname can be overriden by defining the `AITUBE_URL` environment variable.
|
78 |
+
|
79 |
+
eg:
|
80 |
+
|
81 |
+
```bash
|
82 |
+
AITUBE_URL=http://localhost:3000
|
83 |
+
```
|
84 |
+
|
85 |
+
## Build Instructions
|
86 |
+
|
87 |
+
Install [Bun](https://bun.sh/)
|
88 |
+
|
89 |
+
Run the following commands:
|
90 |
+
|
91 |
+
```bash
|
92 |
+
bun install
|
93 |
+
|
94 |
+
bun run build
|
95 |
+
```
|
96 |
+
|
97 |
+
To publish:
|
98 |
+
|
99 |
+
```bash
|
100 |
+
bun run build
|
101 |
+
|
102 |
+
bun run build:declaration
|
103 |
+
|
104 |
+
bun run publish
|
105 |
+
```
|
106 |
+
|
107 |
+
## Contributing
|
108 |
+
|
109 |
+
We welcome contributions! Please feel free to submit a pull request.
|
110 |
+
|
111 |
+
## License
|
112 |
+
|
113 |
+
This package is under the MIT License. See `LICENSE` file for more details.
|
packages/client/package.json
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "@aitube/client",
|
3 |
+
"module": "index.ts",
|
4 |
+
"main": "dist/index.js",
|
5 |
+
"types": "dist/index.d.ts",
|
6 |
+
"type": "module",
|
7 |
+
"version": "0.2.4-3",
|
8 |
+
"description": "Official API client for AiTube.at",
|
9 |
+
"scripts": {
|
10 |
+
"build": "bun build ./src/index.ts --outfile=dist/index.js --external=@aitube/clap && bun run build:declaration",
|
11 |
+
"build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json",
|
12 |
+
"postbuild": "rimraf tsconfig.types.tsbuildinfo && bun run build:declaration",
|
13 |
+
"publish": "npm publish --access public",
|
14 |
+
"update": "rm -Rf node_modules && rm bun.lockb && bun i && bun run build"
|
15 |
+
},
|
16 |
+
"devDependencies": {
|
17 |
+
"bun-types": "latest",
|
18 |
+
"prettier": "^3.3.3",
|
19 |
+
"rimraf": "^6.0.1",
|
20 |
+
"typescript": "^5.5.4"
|
21 |
+
},
|
22 |
+
"repository": {
|
23 |
+
"type": "git",
|
24 |
+
"url": "https://github.com/jbilcke-hf/aitube-client.git"
|
25 |
+
},
|
26 |
+
"keywords": [
|
27 |
+
"Clapper.app",
|
28 |
+
"AiTube.at",
|
29 |
+
"OpenClap",
|
30 |
+
"AI cinema",
|
31 |
+
"file format",
|
32 |
+
"specification"
|
33 |
+
],
|
34 |
+
"author": "Julian Bilcke",
|
35 |
+
"license": "MIT",
|
36 |
+
"files": [
|
37 |
+
"dist/*.js",
|
38 |
+
"dist/*.d.ts",
|
39 |
+
"dist/**/*.d.ts"
|
40 |
+
],
|
41 |
+
"dependencies": {
|
42 |
+
"@aitube/clap": "workspace:*",
|
43 |
+
"@types/bun": "latest",
|
44 |
+
"query-string": "^9.0.0"
|
45 |
+
}
|
46 |
+
}
|
packages/client/src/api/createClap.ts
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ClapProject, fetchClap } from "@aitube/clap"
|
2 |
+
|
3 |
+
import { aitubeApiUrl } from "@/constants/config"
|
4 |
+
|
5 |
+
import { defaultClapHeight, defaultClapWidth } from "@/constants/defaultValues"
|
6 |
+
|
7 |
+
export async function createClap({
|
8 |
+
prompt,
|
9 |
+
height = defaultClapHeight,
|
10 |
+
width = defaultClapWidth,
|
11 |
+
turbo = false,
|
12 |
+
token,
|
13 |
+
}: {
|
14 |
+
prompt: string
|
15 |
+
height?: number
|
16 |
+
width?: number
|
17 |
+
turbo?: boolean
|
18 |
+
token?: string
|
19 |
+
}): Promise<ClapProject> {
|
20 |
+
|
21 |
+
if (typeof prompt !== "string" || !prompt.length) { throw new Error(`please provide a prompt`) }
|
22 |
+
|
23 |
+
const hasToken = typeof token === "string" && token.length > 0
|
24 |
+
|
25 |
+
const clap = await fetchClap(`${aitubeApiUrl}create`, {
|
26 |
+
method: "POST",
|
27 |
+
headers: {
|
28 |
+
"Content-Type": "application/json",
|
29 |
+
...hasToken && {
|
30 |
+
"Authorization": `Bearer ${token}`
|
31 |
+
}
|
32 |
+
},
|
33 |
+
body: JSON.stringify({
|
34 |
+
prompt,
|
35 |
+
width,
|
36 |
+
height,
|
37 |
+
turbo,
|
38 |
+
}),
|
39 |
+
cache: "no-store",
|
40 |
+
})
|
41 |
+
|
42 |
+
return clap
|
43 |
+
}
|
packages/client/src/api/editClapDialogues.ts
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ClapCompletionMode, ClapProject, fetchClap, removeGeneratedAssetUrls, serializeClap } from "@aitube/clap"
|
2 |
+
import queryString from "query-string"
|
3 |
+
|
4 |
+
import { aitubeApiUrl } from "@/constants/config"
|
5 |
+
import { applyClapCompletion } from "@/utils"
|
6 |
+
|
7 |
+
export async function editClapDialogues({
|
8 |
+
clap,
|
9 |
+
completionMode = ClapCompletionMode.MERGE,
|
10 |
+
turbo = false,
|
11 |
+
token,
|
12 |
+
}: {
|
13 |
+
clap: ClapProject
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Completion mode (optional, defaults to "merge")
|
17 |
+
*
|
18 |
+
* Possible values are:
|
19 |
+
* - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications.
|
20 |
+
* - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming.
|
21 |
+
* - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects.
|
22 |
+
* - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates.
|
23 |
+
*/
|
24 |
+
completionMode?: ClapCompletionMode
|
25 |
+
|
26 |
+
turbo?: boolean
|
27 |
+
|
28 |
+
token?: string
|
29 |
+
}): Promise<ClapProject> {
|
30 |
+
|
31 |
+
if (!clap) { throw new Error(`please provide a valid clap project`) }
|
32 |
+
|
33 |
+
const hasToken = typeof token === "string" && token.length > 0
|
34 |
+
|
35 |
+
const params: Record<string, any> = {}
|
36 |
+
|
37 |
+
if (typeof completionMode === "string") {
|
38 |
+
params.c = completionMode
|
39 |
+
}
|
40 |
+
|
41 |
+
if (turbo) {
|
42 |
+
params.t = "true"
|
43 |
+
}
|
44 |
+
|
45 |
+
const newClap = await fetchClap(
|
46 |
+
`${aitubeApiUrl}edit/dialogues?${queryString.stringify(params)}`, {
|
47 |
+
method: "POST",
|
48 |
+
headers: {
|
49 |
+
"Content-Type": "application/x-gzip",
|
50 |
+
...hasToken && {
|
51 |
+
"Authorization": `Bearer ${token}`
|
52 |
+
}
|
53 |
+
},
|
54 |
+
body: await serializeClap(removeGeneratedAssetUrls(clap)),
|
55 |
+
cache: "no-store",
|
56 |
+
})
|
57 |
+
|
58 |
+
const result = await applyClapCompletion(clap, newClap, completionMode)
|
59 |
+
|
60 |
+
return result
|
61 |
+
}
|
packages/client/src/api/editClapEntities.ts
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap"
|
2 |
+
import queryString from "query-string"
|
3 |
+
|
4 |
+
import { aitubeApiUrl } from "@/constants/config"
|
5 |
+
import { ClapEntityPrompt } from "@/constants/types"
|
6 |
+
import { applyClapCompletion } from "@/utils"
|
7 |
+
|
8 |
+
export async function editClapEntities({
|
9 |
+
clap,
|
10 |
+
entityPrompts = [],
|
11 |
+
completionMode = ClapCompletionMode.MERGE,
|
12 |
+
turbo = false,
|
13 |
+
token,
|
14 |
+
}: {
|
15 |
+
// A ClapProject instance
|
16 |
+
clap: ClapProject
|
17 |
+
|
18 |
+
// a list of entity prompts
|
19 |
+
entityPrompts?: ClapEntityPrompt[],
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Completion mode (optional, defaults to "merge")
|
23 |
+
*
|
24 |
+
* Possible values are:
|
25 |
+
* - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications.
|
26 |
+
* - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming.
|
27 |
+
* - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects.
|
28 |
+
* - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates.
|
29 |
+
*/
|
30 |
+
completionMode?: ClapCompletionMode
|
31 |
+
|
32 |
+
turbo?: boolean
|
33 |
+
|
34 |
+
token?: string
|
35 |
+
}): Promise<ClapProject> {
|
36 |
+
|
37 |
+
if (!clap) { throw new Error(`please provide a clap to extend`) }
|
38 |
+
|
39 |
+
const hasToken = typeof token === "string" && token.length > 0
|
40 |
+
|
41 |
+
const params: Record<string, any> = {}
|
42 |
+
|
43 |
+
if (typeof completionMode === "string") {
|
44 |
+
params.c = completionMode
|
45 |
+
}
|
46 |
+
|
47 |
+
if (turbo) {
|
48 |
+
params.t = "true"
|
49 |
+
}
|
50 |
+
|
51 |
+
if (entityPrompts.length) {
|
52 |
+
// if "params.e = JSON.stringify(item)" works with UTF-8 characters,
|
53 |
+
// then we don't need to import "js-base64"
|
54 |
+
// otherwise you will have to do:
|
55 |
+
// params.e = jsBase64.encode(JSON.stringify(item))
|
56 |
+
params.e = JSON.stringify(entityPrompts)
|
57 |
+
}
|
58 |
+
|
59 |
+
const newClap = await fetchClap(
|
60 |
+
`${aitubeApiUrl}edit/entities?${queryString.stringify(params)}`, {
|
61 |
+
method: "POST",
|
62 |
+
headers: {
|
63 |
+
"Content-Type": "application/x-gzip",
|
64 |
+
...hasToken && {
|
65 |
+
"Authorization": `Bearer ${token}`
|
66 |
+
}
|
67 |
+
},
|
68 |
+
body: await serializeClap(removeGeneratedAssetUrls(clap)),
|
69 |
+
cache: "no-store",
|
70 |
+
})
|
71 |
+
|
72 |
+
const result = await applyClapCompletion(clap, newClap, completionMode)
|
73 |
+
|
74 |
+
return result
|
75 |
+
}
|
packages/client/src/api/editClapMusic.ts
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import queryString from "query-string"
|
2 |
+
import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap"
|
3 |
+
|
4 |
+
import { aitubeApiUrl } from "@/constants/config"
|
5 |
+
import { applyClapCompletion } from "@/utils"
|
6 |
+
|
7 |
+
export async function editClapMusic({
|
8 |
+
clap,
|
9 |
+
completionMode = ClapCompletionMode.MERGE,
|
10 |
+
turbo = false,
|
11 |
+
token,
|
12 |
+
}: {
|
13 |
+
clap: ClapProject
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Completion mode (optional, defaults to "merge")
|
17 |
+
*
|
18 |
+
* Possible values are:
|
19 |
+
* - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications.
|
20 |
+
* - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming.
|
21 |
+
* - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects.
|
22 |
+
* - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates.
|
23 |
+
*/
|
24 |
+
completionMode?: ClapCompletionMode
|
25 |
+
|
26 |
+
turbo?: boolean
|
27 |
+
|
28 |
+
token?: string
|
29 |
+
}): Promise<ClapProject> {
|
30 |
+
|
31 |
+
if (!clap) { throw new Error(`please provide a valid clap project`) }
|
32 |
+
|
33 |
+
const hasToken = typeof token === "string" && token.length > 0
|
34 |
+
|
35 |
+
const params: Record<string, any> = {}
|
36 |
+
|
37 |
+
if (typeof completionMode === "string") {
|
38 |
+
params.c = completionMode
|
39 |
+
}
|
40 |
+
|
41 |
+
if (turbo) {
|
42 |
+
params.t = "true"
|
43 |
+
}
|
44 |
+
|
45 |
+
const newClap = await fetchClap(`${aitubeApiUrl}edit/music?${queryString.stringify(params)}`, {
|
46 |
+
method: "POST",
|
47 |
+
headers: {
|
48 |
+
"Content-Type": "application/x-gzip",
|
49 |
+
...hasToken && {
|
50 |
+
"Authorization": `Bearer ${token}`
|
51 |
+
}
|
52 |
+
},
|
53 |
+
body: await serializeClap(removeGeneratedAssetUrls(clap)),
|
54 |
+
cache: "no-store",
|
55 |
+
})
|
56 |
+
|
57 |
+
const result = await applyClapCompletion(clap, newClap, completionMode)
|
58 |
+
|
59 |
+
return result
|
60 |
+
}
|
packages/client/src/api/editClapSounds.ts
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import queryString from "query-string"
|
2 |
+
import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap"
|
3 |
+
|
4 |
+
import { aitubeApiUrl } from "@/constants/config"
|
5 |
+
import { applyClapCompletion } from "@/utils"
|
6 |
+
|
7 |
+
export async function editClapSounds({
|
8 |
+
clap,
|
9 |
+
completionMode = ClapCompletionMode.MERGE,
|
10 |
+
turbo = false,
|
11 |
+
token,
|
12 |
+
}: {
|
13 |
+
clap: ClapProject
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Completion mode (optional, defaults to "merge")
|
17 |
+
*
|
18 |
+
* Possible values are:
|
19 |
+
* - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications.
|
20 |
+
* - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming.
|
21 |
+
* - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects.
|
22 |
+
* - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates.
|
23 |
+
*/
|
24 |
+
completionMode?: ClapCompletionMode
|
25 |
+
|
26 |
+
turbo?: boolean
|
27 |
+
|
28 |
+
token?: string
|
29 |
+
}): Promise<ClapProject> {
|
30 |
+
|
31 |
+
if (!clap) { throw new Error(`please provide a valid clap project`) }
|
32 |
+
|
33 |
+
const hasToken = typeof token === "string" && token.length > 0
|
34 |
+
|
35 |
+
const params: Record<string, any> = {}
|
36 |
+
|
37 |
+
if (typeof completionMode === "string") {
|
38 |
+
params.c = completionMode
|
39 |
+
}
|
40 |
+
|
41 |
+
if (turbo) {
|
42 |
+
params.t = "true"
|
43 |
+
}
|
44 |
+
|
45 |
+
const newClap = await fetchClap(`${aitubeApiUrl}edit/sounds?${queryString.stringify(params)}`, {
|
46 |
+
method: "POST",
|
47 |
+
headers: {
|
48 |
+
"Content-Type": "application/x-gzip",
|
49 |
+
...hasToken && {
|
50 |
+
"Authorization": `Bearer ${token}`
|
51 |
+
}
|
52 |
+
},
|
53 |
+
body: await serializeClap(removeGeneratedAssetUrls(clap)),
|
54 |
+
cache: "no-store",
|
55 |
+
})
|
56 |
+
|
57 |
+
const result = await applyClapCompletion(clap, newClap, completionMode)
|
58 |
+
|
59 |
+
return result
|
60 |
+
}
|
packages/client/src/api/editClapStory.ts
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ClapCompletionMode, ClapProject, fetchClap, filterAssets, isValidNumber, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap"
|
2 |
+
import queryString from "query-string"
|
3 |
+
|
4 |
+
import { aitubeApiUrl } from "@/constants/config"
|
5 |
+
import { applyClapCompletion } from "@/utils"
|
6 |
+
|
7 |
+
export async function editClapStory({
|
8 |
+
clap,
|
9 |
+
prompt,
|
10 |
+
startTimeInMs,
|
11 |
+
endTimeInMs,
|
12 |
+
completionMode = ClapCompletionMode.MERGE,
|
13 |
+
turbo = false,
|
14 |
+
token,
|
15 |
+
}: {
|
16 |
+
// A ClapProject instance
|
17 |
+
clap: ClapProject
|
18 |
+
|
19 |
+
// a prompt to describe how to extend the story (optional)
|
20 |
+
prompt?: string
|
21 |
+
|
22 |
+
// indicates where the completion should start in the timeline
|
23 |
+
//
|
24 |
+
// this can be used tp jump to arbitrary timestamps
|
25 |
+
// in the story
|
26 |
+
//
|
27 |
+
// if you pick a start time AFTER the current project's end time,
|
28 |
+
// the project will be extended
|
29 |
+
//
|
30 |
+
// default value: the current project's end time
|
31 |
+
startTimeInMs?: number
|
32 |
+
|
33 |
+
// it is recommended to use a
|
34 |
+
// end time (eg. startTimeInMs + 12000)
|
35 |
+
// if left by default, th server will generate
|
36 |
+
//
|
37 |
+
// for performance and security reasons,
|
38 |
+
// the server may enforce a hardcoded limit to bypass what you
|
39 |
+
// set here, but that is not a big deal because you can pass
|
40 |
+
// you .clap file again if necessary
|
41 |
+
//
|
42 |
+
// default value: no limit (the server will set one)
|
43 |
+
endTimeInMs?: number
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Completion mode (optional, defaults to "merge")
|
47 |
+
*
|
48 |
+
* Possible values are:
|
49 |
+
* - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications.
|
50 |
+
* - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming.
|
51 |
+
* - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects.
|
52 |
+
* - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates.
|
53 |
+
*/
|
54 |
+
completionMode?: ClapCompletionMode
|
55 |
+
|
56 |
+
turbo?: boolean
|
57 |
+
|
58 |
+
token?: string
|
59 |
+
}): Promise<ClapProject> {
|
60 |
+
|
61 |
+
if (!clap) { throw new Error(`please provide a clap to extend`) }
|
62 |
+
|
63 |
+
const hasToken = typeof token === "string" && token.length > 0
|
64 |
+
|
65 |
+
const params: Record<string, any> = {}
|
66 |
+
|
67 |
+
if (typeof completionMode === "string") {
|
68 |
+
params.c = completionMode
|
69 |
+
}
|
70 |
+
|
71 |
+
if (typeof prompt === "string" && prompt.length > 0) {
|
72 |
+
params.p = prompt
|
73 |
+
}
|
74 |
+
|
75 |
+
if (isValidNumber(startTimeInMs)) {
|
76 |
+
params.s = startTimeInMs
|
77 |
+
}
|
78 |
+
|
79 |
+
if (isValidNumber(endTimeInMs)) {
|
80 |
+
params.e = endTimeInMs
|
81 |
+
}
|
82 |
+
|
83 |
+
if (turbo) {
|
84 |
+
params.t = "true"
|
85 |
+
}
|
86 |
+
|
87 |
+
// we remove heavy elements from the payload
|
88 |
+
const payload = await filterAssets({
|
89 |
+
clap,
|
90 |
+
mode: "INCLUDE",
|
91 |
+
categories: {},
|
92 |
+
immutable: true, // to create a standalone copy
|
93 |
+
|
94 |
+
// we only remove the data, but we still keep things marked as "generated"
|
95 |
+
updateStatus: false,
|
96 |
+
})
|
97 |
+
|
98 |
+
const newClap = await fetchClap(
|
99 |
+
`${aitubeApiUrl}edit/story?${queryString.stringify(params)}`, {
|
100 |
+
method: "POST",
|
101 |
+
headers: {
|
102 |
+
"Content-Type": "application/x-gzip",
|
103 |
+
...hasToken && {
|
104 |
+
"Authorization": `Bearer ${token}`
|
105 |
+
}
|
106 |
+
},
|
107 |
+
body: await serializeClap(removeGeneratedAssetUrls(clap)),
|
108 |
+
cache: "no-store",
|
109 |
+
})
|
110 |
+
|
111 |
+
const result = await applyClapCompletion(clap, newClap, completionMode)
|
112 |
+
|
113 |
+
return result
|
114 |
+
}
|
packages/client/src/api/editClapStoryboards.ts
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import queryString from "query-string"
|
2 |
+
import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls } from "@aitube/clap"
|
3 |
+
|
4 |
+
import { aitubeApiUrl } from "@/constants/config"
|
5 |
+
import { applyClapCompletion } from "@/utils"
|
6 |
+
|
7 |
+
export async function editClapStoryboards({
|
8 |
+
clap,
|
9 |
+
completionMode = ClapCompletionMode.MERGE,
|
10 |
+
turbo = false,
|
11 |
+
token,
|
12 |
+
}: {
|
13 |
+
clap: ClapProject
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Completion mode (optional, defaults to "merge")
|
17 |
+
*
|
18 |
+
* Possible values are:
|
19 |
+
* - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications.
|
20 |
+
* - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming.
|
21 |
+
* - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects.
|
22 |
+
* - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates.
|
23 |
+
*/
|
24 |
+
completionMode?: ClapCompletionMode
|
25 |
+
|
26 |
+
turbo?: boolean
|
27 |
+
|
28 |
+
token?: string
|
29 |
+
}): Promise<ClapProject> {
|
30 |
+
|
31 |
+
if (!clap) { throw new Error(`please provide a valid clap project`) }
|
32 |
+
|
33 |
+
const hasToken = typeof token === "string" && token.length > 0
|
34 |
+
|
35 |
+
const params: Record<string, any> = {}
|
36 |
+
|
37 |
+
if (typeof completionMode === "string") {
|
38 |
+
params.c = completionMode
|
39 |
+
}
|
40 |
+
|
41 |
+
if (turbo) {
|
42 |
+
params.t = "true"
|
43 |
+
}
|
44 |
+
|
45 |
+
const newClap = await fetchClap(`${aitubeApiUrl}edit/storyboards?${queryString.stringify(params)}`, {
|
46 |
+
method: "POST",
|
47 |
+
headers: {
|
48 |
+
"Content-Type": "application/x-gzip",
|
49 |
+
...hasToken && {
|
50 |
+
"Authorization": `Bearer ${token}`
|
51 |
+
}
|
52 |
+
},
|
53 |
+
body: await serializeClap(removeGeneratedAssetUrls(clap)),
|
54 |
+
cache: "no-store",
|
55 |
+
})
|
56 |
+
|
57 |
+
const result = await applyClapCompletion(clap, newClap, completionMode)
|
58 |
+
|
59 |
+
return result
|
60 |
+
}
|
packages/client/src/api/editClapVideos.ts
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import queryString from "query-string"
|
2 |
+
import { ClapCompletionMode, ClapProject, fetchClap, serializeClap, removeGeneratedAssetUrls, ClapSegmentStatus, ClapSegmentCategory, filterSegments, ClapSegmentFilteringMode, ClapSegment } from "@aitube/clap"
|
3 |
+
|
4 |
+
import { aitubeApiUrl } from "@/constants/config"
|
5 |
+
import { applyClapCompletion } from "@/utils"
|
6 |
+
|
7 |
+
export async function editClapVideos({
|
8 |
+
clap,
|
9 |
+
completionMode = ClapCompletionMode.MERGE,
|
10 |
+
turbo = false,
|
11 |
+
token,
|
12 |
+
}: {
|
13 |
+
clap: ClapProject
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Completion mode (optional, defaults to "merge")
|
17 |
+
*
|
18 |
+
* Possible values are:
|
19 |
+
* - full: the API and the client will return a full clap file. This is a very convenient and simple mode, but it is also very ineficient, so it should not be used for intensive applications.
|
20 |
+
* - partial: the API and the client will return a partial clap file, containing only the new values and changes. This is useful for real-time applications and streaming.
|
21 |
+
* - merge: the API will return a partial clap file, and the client will return a merge of the original with the new values. This is safe to run, there are no side-effects.
|
22 |
+
* - replace: the API will return a partial clap file, and the client will replace the original. This is the most efficient mode, but it relies on side-effects and inline object updates.
|
23 |
+
*/
|
24 |
+
completionMode?: ClapCompletionMode
|
25 |
+
|
26 |
+
turbo?: boolean
|
27 |
+
|
28 |
+
token?: string
|
29 |
+
}): Promise<ClapProject> {
|
30 |
+
|
31 |
+
if (!clap) { throw new Error(`please provide a valid clap project`) }
|
32 |
+
|
33 |
+
const hasToken = typeof token === "string" && token.length > 0
|
34 |
+
|
35 |
+
const params: Record<string, any> = {}
|
36 |
+
|
37 |
+
if (typeof completionMode === "string") {
|
38 |
+
params.c = completionMode
|
39 |
+
}
|
40 |
+
|
41 |
+
if (turbo) {
|
42 |
+
params.t = "true"
|
43 |
+
}
|
44 |
+
// special trick to not touch the generated
|
45 |
+
// storyboard images that are used by pending videos
|
46 |
+
const idsOfStoryboardsToKeep = clap.segments.map((segment: ClapSegment) => {
|
47 |
+
|
48 |
+
const isPendingVideo = (
|
49 |
+
segment.category === ClapSegmentCategory.VIDEO
|
50 |
+
&&
|
51 |
+
segment.status === ClapSegmentStatus.TO_GENERATE
|
52 |
+
)
|
53 |
+
|
54 |
+
if (!isPendingVideo) { return undefined }
|
55 |
+
|
56 |
+
const storyboardImage: ClapSegment | undefined = filterSegments(
|
57 |
+
ClapSegmentFilteringMode.BOTH,
|
58 |
+
segment,
|
59 |
+
clap.segments,
|
60 |
+
ClapSegmentCategory.IMAGE
|
61 |
+
).at(0)
|
62 |
+
|
63 |
+
return storyboardImage?.id
|
64 |
+
}).filter((x: any) => x) as string[]
|
65 |
+
|
66 |
+
const newClap = await fetchClap(`${aitubeApiUrl}edit/videos?${queryString.stringify(params)}`, {
|
67 |
+
method: "POST",
|
68 |
+
headers: {
|
69 |
+
"Content-Type": "application/x-gzip",
|
70 |
+
...hasToken && {
|
71 |
+
"Authorization": `Bearer ${token}`
|
72 |
+
}
|
73 |
+
},
|
74 |
+
body: await serializeClap(
|
75 |
+
// need a special trick here, to not touch the generated
|
76 |
+
// storyboards that are used by pending videos
|
77 |
+
removeGeneratedAssetUrls(clap, idsOfStoryboardsToKeep)
|
78 |
+
),
|
79 |
+
cache: "no-store",
|
80 |
+
})
|
81 |
+
|
82 |
+
const result = await applyClapCompletion(clap, newClap, completionMode)
|
83 |
+
|
84 |
+
return result
|
85 |
+
}
|
packages/client/src/api/exportClapToVideo.ts
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import queryString from "query-string"
|
2 |
+
import { ClapProject, serializeClap, blobToDataUri } from "@aitube/clap"
|
3 |
+
|
4 |
+
import { aitubeApiUrl } from "@/constants/config"
|
5 |
+
import { defaultExportFormat, SupportedExportFormat } from "@/constants"
|
6 |
+
|
7 |
+
|
8 |
+
export async function exportClapToVideo({
|
9 |
+
clap,
|
10 |
+
format = defaultExportFormat,
|
11 |
+
turbo = false,
|
12 |
+
token,
|
13 |
+
}: {
|
14 |
+
clap: ClapProject
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Desired output video format (defaults to "mp4")
|
18 |
+
*
|
19 |
+
* Can be either "mp4" or "webm"
|
20 |
+
*/
|
21 |
+
format?: SupportedExportFormat
|
22 |
+
|
23 |
+
turbo?: boolean
|
24 |
+
|
25 |
+
token?: string
|
26 |
+
}): Promise<string> {
|
27 |
+
|
28 |
+
if (!clap) { throw new Error(`please provide a clap`) }
|
29 |
+
|
30 |
+
// TODO use an enum instead, and check the enum object
|
31 |
+
if (format !== "mp4" && format !== "webm") { throw new Error(`please provide a valid format ("${format}" is unrecognized)`) }
|
32 |
+
|
33 |
+
const params: Record<string, any> = {}
|
34 |
+
|
35 |
+
params.f = format
|
36 |
+
|
37 |
+
if (turbo) {
|
38 |
+
params.t = "true"
|
39 |
+
}
|
40 |
+
|
41 |
+
const hasToken = typeof token === "string" && token.length > 0
|
42 |
+
|
43 |
+
const res = await fetch(`${aitubeApiUrl}export?${queryString.stringify(params)}`, {
|
44 |
+
method: "POST",
|
45 |
+
headers: {
|
46 |
+
"Content-Type": "application/x-gzip",
|
47 |
+
...hasToken && {
|
48 |
+
"Authorization": `Bearer ${token}`
|
49 |
+
}
|
50 |
+
},
|
51 |
+
body: await serializeClap(clap),
|
52 |
+
cache: "no-store",
|
53 |
+
})
|
54 |
+
|
55 |
+
const blob = await res.blob()
|
56 |
+
|
57 |
+
const dataURL = await blobToDataUri(blob)
|
58 |
+
|
59 |
+
return dataURL
|
60 |
+
}
|
packages/client/src/api/index.ts
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export { createClap } from "./createClap"
|
2 |
+
export { editClapDialogues } from "./editClapDialogues"
|
3 |
+
export { editClapEntities } from "./editClapEntities"
|
4 |
+
export { editClapMusic } from "./editClapMusic"
|
5 |
+
export { editClapSounds } from "./editClapSounds"
|
6 |
+
export { editClapStory } from "./editClapStory"
|
7 |
+
export { editClapStoryboards } from "./editClapStoryboards"
|
8 |
+
export { editClapVideos } from "./editClapVideos"
|
9 |
+
export { exportClapToVideo } from "./exportClapToVideo"
|
packages/client/src/constants/config.ts
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { defaultAitubeHostname } from "./defaultValues"
|
2 |
+
|
3 |
+
// we leave the opportunity to override this at runtime
|
4 |
+
export const aitubeUrl = `${
|
5 |
+
process.env.AITUBE_URL ||
|
6 |
+
`https://${defaultAitubeHostname}`
|
7 |
+
}`
|
8 |
+
|
9 |
+
// note: let's keep it simple and only support one version at a time
|
10 |
+
export const aitubeApiVersion = "v1"
|
11 |
+
|
12 |
+
export const aitubeApiUrl = `${
|
13 |
+
aitubeUrl
|
14 |
+
}${
|
15 |
+
aitubeUrl.endsWith("/") ? "" : "/"
|
16 |
+
}api/${aitubeApiVersion}/`
|
packages/client/src/constants/defaultValues.ts
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// unfortunately, this doesn't work yet due to a redirection issue
|
2 |
+
// const defaultAitubeHostname = "aitube.at"
|
3 |
+
|
4 |
+
// so we have to use the direct space hostname instead
|
5 |
+
export const defaultAitubeHostname = "aitube.at"
|
6 |
+
|
7 |
+
export const defaultClapWidth = 512
|
8 |
+
export const defaultClapHeight = 288
|
9 |
+
|
10 |
+
export const defaultExportFormat = "mp4"
|
packages/client/src/constants/index.ts
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export {
|
2 |
+
defaultAitubeHostname,
|
3 |
+
defaultClapWidth,
|
4 |
+
defaultClapHeight,
|
5 |
+
defaultExportFormat
|
6 |
+
} from './defaultValues'
|
7 |
+
|
8 |
+
export {
|
9 |
+
aitubeUrl,
|
10 |
+
aitubeApiVersion,
|
11 |
+
aitubeApiUrl
|
12 |
+
} from './config'
|
13 |
+
|
14 |
+
export {
|
15 |
+
ClapEntityPrompt,
|
16 |
+
SupportedExportFormat
|
17 |
+
} from "./types"
|
packages/client/src/constants/types.ts
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ClapSegmentCategory } from "@aitube/clap"
|
2 |
+
|
3 |
+
export type SupportedExportFormat = "mp4" | "webm"
|
4 |
+
|
5 |
+
export type ClapEntityPrompt = {
|
6 |
+
name: string
|
7 |
+
|
8 |
+
// eg. "character", "location"
|
9 |
+
category: ClapSegmentCategory
|
10 |
+
|
11 |
+
// age of the person, animal or entity (eg. robot, talking spaceship etc)
|
12 |
+
age: string
|
13 |
+
|
14 |
+
// characterization of the person, animal or entity (texture, hair color, gender etc)
|
15 |
+
variant: string
|
16 |
+
|
17 |
+
// region from where the person, animal or entity is coming from (human, mechanical, alien planet, european, south-american etc)
|
18 |
+
region: string
|
19 |
+
|
20 |
+
// identity picture
|
21 |
+
identityImage: string
|
22 |
+
|
23 |
+
// identity voice
|
24 |
+
identityVoice: string
|
25 |
+
}
|
packages/client/src/index.ts
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
export {
|
3 |
+
createClap,
|
4 |
+
editClapDialogues,
|
5 |
+
editClapEntities,
|
6 |
+
editClapMusic,
|
7 |
+
editClapSounds,
|
8 |
+
editClapStory,
|
9 |
+
editClapStoryboards,
|
10 |
+
editClapVideos,
|
11 |
+
exportClapToVideo,
|
12 |
+
} from './api'
|
13 |
+
|
14 |
+
export {
|
15 |
+
defaultAitubeHostname,
|
16 |
+
defaultClapWidth,
|
17 |
+
defaultClapHeight,
|
18 |
+
defaultExportFormat,
|
19 |
+
aitubeUrl,
|
20 |
+
aitubeApiVersion,
|
21 |
+
aitubeApiUrl,
|
22 |
+
ClapEntityPrompt,
|
23 |
+
SupportedExportFormat
|
24 |
+
} from "./constants"
|
25 |
+
|
26 |
+
export {
|
27 |
+
applyClapCompletion,
|
28 |
+
} from "./utils"
|
packages/client/src/parsers/index.ts
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
export { parseEntityPrompt } from "./parseEntityPrompt"
|
2 |
+
export { parseString } from "./parseString"
|
3 |
+
export { parseStringArray } from "./parseStringArray"
|
packages/client/src/parsers/parseEntityPrompt.ts
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
|
3 |
+
import { ClapEntityPrompt } from "@/constants/types"
|
4 |
+
|
5 |
+
import { parseString } from "./parseString"
|
6 |
+
import { ClapSegmentCategory } from "@aitube/clap"
|
7 |
+
|
8 |
+
export function parseEntityPrompt(entityPrompt: Partial<ClapEntityPrompt> = {}): ClapEntityPrompt {
|
9 |
+
|
10 |
+
return {
|
11 |
+
name: parseString(entityPrompt?.name),
|
12 |
+
|
13 |
+
category: parseString(entityPrompt?.category) as ClapSegmentCategory,
|
14 |
+
|
15 |
+
// age of the person, animal or entity (eg. robot, talking spaceship etc)
|
16 |
+
age: parseString(entityPrompt?.age),
|
17 |
+
|
18 |
+
// characterization of the person, animal or entity (texture, hair color, gender etc)
|
19 |
+
variant: parseString(entityPrompt?.variant),
|
20 |
+
|
21 |
+
// region from where the person, animal or entity is coming from (human, mechanical, alien planet, european, south-american etc)
|
22 |
+
region: parseString(entityPrompt?.region),
|
23 |
+
|
24 |
+
// identity picture
|
25 |
+
identityImage: parseString(entityPrompt?.identityImage),
|
26 |
+
|
27 |
+
// identity voice
|
28 |
+
identityVoice: parseString(entityPrompt?.identityVoice),
|
29 |
+
}
|
30 |
+
}
|
packages/client/src/parsers/parseString.ts
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export function parseString(input?: any, defaultValue?: string): string {
|
2 |
+
const defValue = `${defaultValue || ""}`
|
3 |
+
|
4 |
+
if (typeof input !== "string") { return defValue }
|
5 |
+
|
6 |
+
return input || defValue
|
7 |
+
}
|
packages/client/src/parsers/parseStringArray.ts
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export function parseStringArray(something: any): string[] {
|
2 |
+
let result: string[] = []
|
3 |
+
if (typeof something === "string") {
|
4 |
+
result = [something]
|
5 |
+
} else if (Array.isArray(something)) {
|
6 |
+
result = something.map(thing => typeof thing === "string" ? thing : "").filter(x => x)
|
7 |
+
}
|
8 |
+
return result
|
9 |
+
}
|
packages/client/src/utils/applyClapCompletion.ts
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ClapCompletionMode, ClapProject, updateClap } from "@aitube/clap"
|
2 |
+
|
3 |
+
export async function applyClapCompletion(
|
4 |
+
existingClap: ClapProject,
|
5 |
+
newerClap: ClapProject,
|
6 |
+
clapCompletionMode: ClapCompletionMode
|
7 |
+
): Promise<ClapProject> {
|
8 |
+
// in both those mode we leave full control to what is inside "newerClap"
|
9 |
+
if (clapCompletionMode === ClapCompletionMode.FULL || clapCompletionMode === ClapCompletionMode.PARTIAL) {
|
10 |
+
return newerClap
|
11 |
+
}
|
12 |
+
|
13 |
+
// else we are in ClapCompletionMode.MERGE or ClapCompletionMode.REPLACE
|
14 |
+
const result = await updateClap(existingClap, newerClap, {
|
15 |
+
// the newer clap meta may contain incomplete information
|
16 |
+
overwriteMeta: false,
|
17 |
+
inlineReplace: clapCompletionMode === ClapCompletionMode.REPLACE
|
18 |
+
})
|
19 |
+
|
20 |
+
return result
|
21 |
+
}
|
packages/client/src/utils/index.ts
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
export { applyClapCompletion } from "./applyClapCompletion"
|
packages/client/tsconfig.json
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"compilerOptions": {
|
3 |
+
"outDir": "./dist",
|
4 |
+
"rootDir": "./src",
|
5 |
+
"baseUrl": "./",
|
6 |
+
"paths": {
|
7 |
+
"@/*": ["src/*"]
|
8 |
+
},
|
9 |
+
"lib": ["ESNext", "DOM"],
|
10 |
+
"module": "esnext",
|
11 |
+
"target": "esnext",
|
12 |
+
"moduleResolution": "bundler",
|
13 |
+
"moduleDetection": "force",
|
14 |
+
"allowImportingTsExtensions": true,
|
15 |
+
"noEmit": true,
|
16 |
+
"composite": true,
|
17 |
+
"strict": true,
|
18 |
+
"downlevelIteration": true,
|
19 |
+
"skipLibCheck": true,
|
20 |
+
"jsx": "react-jsx",
|
21 |
+
"allowSyntheticDefaultImports": true,
|
22 |
+
"forceConsistentCasingInFileNames": true,
|
23 |
+
"allowJs": true,
|
24 |
+
"types": [
|
25 |
+
"bun-types"
|
26 |
+
]
|
27 |
+
},
|
28 |
+
"include": [
|
29 |
+
"src/**/*.ts"
|
30 |
+
]
|
31 |
+
}
|
packages/client/tsconfig.types.json
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"extends": "./tsconfig.json",
|
3 |
+
"compilerOptions": {
|
4 |
+
"noEmit": false,
|
5 |
+
"emitDeclarationOnly": true,
|
6 |
+
"declaration": true,
|
7 |
+
"outDir": "./dist",
|
8 |
+
"rootDir": "./src",
|
9 |
+
},
|
10 |
+
"include": [
|
11 |
+
"src/**/*.ts"
|
12 |
+
]
|
13 |
+
}
|