vargai 0.4.0-alpha56 → 0.4.0-alpha57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# fal.ai api key
|
|
2
|
+
FAL_API_KEY=fal_xxx
|
|
3
|
+
|
|
4
|
+
# higgsfield credentials
|
|
5
|
+
HIGGSFIELD_API_KEY=hf_xxx
|
|
6
|
+
HIGGSFIELD_SECRET=secret_xxx
|
|
7
|
+
|
|
8
|
+
# elevenlabs api key
|
|
9
|
+
ELEVENLABS_API_KEY=el_xxx
|
|
10
|
+
|
|
11
|
+
# groq api key (ultra-fast whisper transcription)
|
|
12
|
+
GROQ_API_KEY=gsk_xxx
|
|
13
|
+
|
|
14
|
+
# fireworks api key (word-level transcription with timestamps)
|
|
15
|
+
FIREWORKS_API_KEY=fw_xxx
|
|
16
|
+
|
|
17
|
+
# cloudflare r2 / s3 storage
|
|
18
|
+
CLOUDFLARE_R2_API_URL=https://xxx.r2.cloudflarestorage.com
|
|
19
|
+
CLOUDFLARE_ACCESS_KEY_ID=xxx
|
|
20
|
+
CLOUDFLARE_ACCESS_SECRET=xxx
|
|
21
|
+
CLOUDFLARE_R2_BUCKET=m
|
|
22
|
+
|
|
23
|
+
# replicate (optional)
|
|
24
|
+
REPLICATE_API_TOKEN=r8_xxx
|
|
25
|
+
|
|
26
|
+
# apify (web scraping actors)
|
|
27
|
+
APIFY_TOKEN=apify_api_xxx
|
|
28
|
+
|
|
29
|
+
# decart ai (real-time & batch video/image)
|
|
30
|
+
DECART_API_KEY=decart_xxx
|
|
31
|
+
|
|
32
|
+
# together ai (fast flux-schnell, no queue)
|
|
33
|
+
TOGETHER_API_KEY=together_xxx
|
package/package.json
CHANGED
|
@@ -3,28 +3,17 @@ import type {
|
|
|
3
3
|
FFmpegBackend,
|
|
4
4
|
FFmpegOutput,
|
|
5
5
|
} from "../../ai-sdk/providers/editly/backends/types";
|
|
6
|
-
import { uploadBuffer } from "../../providers/storage";
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
|
-
* Resolves an FFmpegOutput to a string path/URL
|
|
10
|
-
*
|
|
11
|
-
* - URL input → returns URL as-is
|
|
12
|
-
* - File input + shouldUpload=false → returns local path
|
|
13
|
-
* - File input + shouldUpload=true → uploads to storage, returns URL
|
|
8
|
+
* Resolves an FFmpegOutput to a string path/URL via the backend.
|
|
9
|
+
* Local backend returns local paths; cloud backends upload and return URLs.
|
|
14
10
|
*/
|
|
15
11
|
async function resolveInputPathMaybeUpload(
|
|
16
12
|
input: FFmpegOutput,
|
|
17
|
-
|
|
13
|
+
backend: FFmpegBackend,
|
|
18
14
|
): Promise<string> {
|
|
19
15
|
if (input.type === "url") return input.url;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const buffer = await Bun.file(input.path).arrayBuffer();
|
|
23
|
-
return uploadBuffer(
|
|
24
|
-
buffer,
|
|
25
|
-
`tmp/${Date.now()}-${input.path.split("/").pop()}`,
|
|
26
|
-
"application/octet-stream",
|
|
27
|
-
);
|
|
16
|
+
return backend.resolvePath(input.path);
|
|
28
17
|
}
|
|
29
18
|
|
|
30
19
|
export interface CaptionOverlayOptions {
|
|
@@ -69,22 +58,15 @@ export async function burnCaptions(
|
|
|
69
58
|
const { video, assPath, outputPath = "output.mp4", verbose } = options;
|
|
70
59
|
const captions: FFmpegOutput = { type: "file", path: assPath };
|
|
71
60
|
|
|
72
|
-
// Resolve backend first so we can check if it's cloud or local
|
|
73
|
-
// TODO: This is a hack - we should abstract backend capabilities (e.g., supportsLocalPaths)
|
|
74
|
-
// instead of checking the name directly. For now, we assume "local" is the only local backend.
|
|
75
61
|
const backend = options.backend ?? localBackend;
|
|
76
|
-
const isCloud = backend.name !== "local";
|
|
77
62
|
|
|
78
|
-
const videoInput = await resolveInputPathMaybeUpload(video,
|
|
79
|
-
|
|
80
|
-
});
|
|
81
|
-
const assInput = await resolveInputPathMaybeUpload(captions, {
|
|
82
|
-
shouldUpload: isCloud,
|
|
83
|
-
});
|
|
63
|
+
const videoInput = await resolveInputPathMaybeUpload(video, backend);
|
|
64
|
+
const assInput = await resolveInputPathMaybeUpload(captions, backend);
|
|
84
65
|
|
|
85
66
|
// For cloud backends (Rendi): pass raw URL so replaceWithPlaceholders() can match
|
|
86
67
|
// and replace with {{in_X}} placeholder. Rendi downloads inputs and provides local paths.
|
|
87
68
|
// For local backend: escape for FFmpeg filter syntax (backslashes and colons)
|
|
69
|
+
const isCloud = backend.name !== "local";
|
|
88
70
|
const subtitlesPath = isCloud
|
|
89
71
|
? assInput
|
|
90
72
|
: assInput.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
|
|
@@ -4,7 +4,6 @@ import type {
|
|
|
4
4
|
FFmpegBackend,
|
|
5
5
|
FFmpegOutput,
|
|
6
6
|
} from "../../../ai-sdk/providers/editly/backends/types";
|
|
7
|
-
import { uploadBuffer } from "../../../providers/storage";
|
|
8
7
|
|
|
9
8
|
export interface BlinkingButtonOptions {
|
|
10
9
|
text: string;
|
|
@@ -107,18 +106,15 @@ function oscExpr(tv: string, P: number): string {
|
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
/**
|
|
110
|
-
* Resolve a local file path to a URL
|
|
109
|
+
* Resolve a local file path to a string path/URL via the backend.
|
|
111
110
|
* Local backend: returns the path as-is.
|
|
112
|
-
* Cloud backend: uploads
|
|
111
|
+
* Cloud backend (Rendi): uploads via its StorageProvider and returns the URL.
|
|
113
112
|
*/
|
|
114
113
|
async function resolvePathForBackend(
|
|
115
114
|
localPath: string,
|
|
116
115
|
backend: FFmpegBackend,
|
|
117
116
|
): Promise<string> {
|
|
118
|
-
|
|
119
|
-
const buffer = await Bun.file(localPath).arrayBuffer();
|
|
120
|
-
const key = `tmp/${Date.now()}-${localPath.split("/").pop()}`;
|
|
121
|
-
return uploadBuffer(buffer, key, "image/png");
|
|
117
|
+
return backend.resolvePath(localPath);
|
|
122
118
|
}
|
|
123
119
|
|
|
124
120
|
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { editly } from "../../ai-sdk/providers/editly";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
FFmpegBackend,
|
|
4
|
+
FFmpegOutput,
|
|
5
|
+
} from "../../ai-sdk/providers/editly/backends/types";
|
|
3
6
|
import type {
|
|
4
7
|
Clip,
|
|
5
8
|
ImageOverlayLayer,
|
|
@@ -9,27 +12,21 @@ import type {
|
|
|
9
12
|
SizeValue,
|
|
10
13
|
TitleLayer,
|
|
11
14
|
} from "../../ai-sdk/providers/editly/types";
|
|
12
|
-
import { uploadBuffer } from "../../providers/storage";
|
|
13
15
|
import type { PackshotProps, VargElement } from "../types";
|
|
14
16
|
import type { RenderContext } from "./context";
|
|
15
17
|
import { renderImage } from "./image";
|
|
16
18
|
import { createBlinkingButton } from "./packshot/blinking-button";
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
|
-
* Resolve an FFmpegOutput to a string path/URL
|
|
21
|
+
* Resolve an FFmpegOutput to a string path/URL via the backend.
|
|
22
|
+
* Local backend returns local paths; cloud backends upload and return URLs.
|
|
20
23
|
*/
|
|
21
24
|
async function resolveInputMaybeUpload(
|
|
22
25
|
input: FFmpegOutput,
|
|
23
|
-
|
|
26
|
+
backend: FFmpegBackend,
|
|
24
27
|
): Promise<string> {
|
|
25
28
|
if (input.type === "url") return input.url;
|
|
26
|
-
|
|
27
|
-
const buffer = await Bun.file(input.path).arrayBuffer();
|
|
28
|
-
return uploadBuffer(
|
|
29
|
-
buffer,
|
|
30
|
-
`tmp/${Date.now()}-${input.path.split("/").pop()}`,
|
|
31
|
-
"application/octet-stream",
|
|
32
|
-
);
|
|
29
|
+
return backend.resolvePath(input.path);
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
/**
|
|
@@ -207,12 +204,11 @@ export async function renderPackshot(
|
|
|
207
204
|
);
|
|
208
205
|
|
|
209
206
|
// Composite button overlay at correct position on base video via backend
|
|
210
|
-
const isCloud = ctx.backend.name !== "local";
|
|
211
207
|
const baseInput = await resolveInputMaybeUpload(
|
|
212
208
|
{ type: "file", path: basePath },
|
|
213
|
-
|
|
209
|
+
ctx.backend,
|
|
214
210
|
);
|
|
215
|
-
const btnInput = await resolveInputMaybeUpload(btn.output,
|
|
211
|
+
const btnInput = await resolveInputMaybeUpload(btn.output, ctx.backend);
|
|
216
212
|
|
|
217
213
|
const finalPath = `/tmp/varg-packshot-final-${Date.now()}.mp4`;
|
|
218
214
|
|