devrel-toolkit 0.1.0
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/README.md +63 -0
- package/dist/__tests__/cli.test.d.ts +2 -0
- package/dist/__tests__/cli.test.d.ts.map +1 -0
- package/dist/__tests__/cli.test.js +47 -0
- package/dist/__tests__/cli.test.js.map +1 -0
- package/dist/__tests__/components.test.d.ts +2 -0
- package/dist/__tests__/components.test.d.ts.map +1 -0
- package/dist/__tests__/components.test.js +73 -0
- package/dist/__tests__/components.test.js.map +1 -0
- package/dist/__tests__/d-id-client.test.d.ts +2 -0
- package/dist/__tests__/d-id-client.test.d.ts.map +1 -0
- package/dist/__tests__/d-id-client.test.js +116 -0
- package/dist/__tests__/d-id-client.test.js.map +1 -0
- package/dist/__tests__/render-integration.test.d.ts +2 -0
- package/dist/__tests__/render-integration.test.d.ts.map +1 -0
- package/dist/__tests__/render-integration.test.js +26 -0
- package/dist/__tests__/render-integration.test.js.map +1 -0
- package/dist/__tests__/schema.test.d.ts +2 -0
- package/dist/__tests__/schema.test.d.ts.map +1 -0
- package/dist/__tests__/schema.test.js +173 -0
- package/dist/__tests__/schema.test.js.map +1 -0
- package/dist/__tests__/timing.test.d.ts +2 -0
- package/dist/__tests__/timing.test.d.ts.map +1 -0
- package/dist/__tests__/timing.test.js +69 -0
- package/dist/__tests__/timing.test.js.map +1 -0
- package/dist/cli/d-id.d.ts +3 -0
- package/dist/cli/d-id.d.ts.map +1 -0
- package/dist/cli/d-id.js +53 -0
- package/dist/cli/d-id.js.map +1 -0
- package/dist/cli/doctor.d.ts +3 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +134 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +21 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/install-skill.d.ts +3 -0
- package/dist/cli/install-skill.d.ts.map +1 -0
- package/dist/cli/install-skill.js +50 -0
- package/dist/cli/install-skill.js.map +1 -0
- package/dist/cli/render.d.ts +4 -0
- package/dist/cli/render.d.ts.map +1 -0
- package/dist/cli/render.js +134 -0
- package/dist/cli/render.js.map +1 -0
- package/dist/cli/setup.d.ts +3 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +60 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/compositor/DemoVideo.d.ts +4 -0
- package/dist/compositor/DemoVideo.d.ts.map +1 -0
- package/dist/compositor/DemoVideo.js +64 -0
- package/dist/compositor/DemoVideo.js.map +1 -0
- package/dist/compositor/Root.d.ts +3 -0
- package/dist/compositor/Root.d.ts.map +1 -0
- package/dist/compositor/Root.js +30 -0
- package/dist/compositor/Root.js.map +1 -0
- package/dist/compositor/components/AvatarPiP.d.ts +10 -0
- package/dist/compositor/components/AvatarPiP.d.ts.map +1 -0
- package/dist/compositor/components/AvatarPiP.js +52 -0
- package/dist/compositor/components/AvatarPiP.js.map +1 -0
- package/dist/compositor/components/BrowserFrame.d.ts +18 -0
- package/dist/compositor/components/BrowserFrame.d.ts.map +1 -0
- package/dist/compositor/components/BrowserFrame.js +97 -0
- package/dist/compositor/components/BrowserFrame.js.map +1 -0
- package/dist/compositor/components/Cursor.d.ts +13 -0
- package/dist/compositor/components/Cursor.d.ts.map +1 -0
- package/dist/compositor/components/Cursor.js +65 -0
- package/dist/compositor/components/Cursor.js.map +1 -0
- package/dist/compositor/components/Highlight.d.ts +9 -0
- package/dist/compositor/components/Highlight.d.ts.map +1 -0
- package/dist/compositor/components/Highlight.js +83 -0
- package/dist/compositor/components/Highlight.js.map +1 -0
- package/dist/compositor/components/IntroOutro.d.ts +10 -0
- package/dist/compositor/components/IntroOutro.d.ts.map +1 -0
- package/dist/compositor/components/IntroOutro.js +48 -0
- package/dist/compositor/components/IntroOutro.js.map +1 -0
- package/dist/compositor/components/SceneTransition.d.ts +9 -0
- package/dist/compositor/components/SceneTransition.d.ts.map +1 -0
- package/dist/compositor/components/SceneTransition.js +35 -0
- package/dist/compositor/components/SceneTransition.js.map +1 -0
- package/dist/compositor/components/Subtitles.d.ts +9 -0
- package/dist/compositor/components/Subtitles.d.ts.map +1 -0
- package/dist/compositor/components/Subtitles.js +45 -0
- package/dist/compositor/components/Subtitles.js.map +1 -0
- package/dist/compositor/index.d.ts +2 -0
- package/dist/compositor/index.d.ts.map +1 -0
- package/dist/compositor/index.js +4 -0
- package/dist/compositor/index.js.map +1 -0
- package/dist/compositor/timing.d.ts +16 -0
- package/dist/compositor/timing.d.ts.map +1 -0
- package/dist/compositor/timing.js +39 -0
- package/dist/compositor/timing.js.map +1 -0
- package/dist/d-id/client.d.ts +50 -0
- package/dist/d-id/client.d.ts.map +1 -0
- package/dist/d-id/client.js +114 -0
- package/dist/d-id/client.js.map +1 -0
- package/dist/d-id/generate.d.ts +9 -0
- package/dist/d-id/generate.d.ts.map +1 -0
- package/dist/d-id/generate.js +81 -0
- package/dist/d-id/generate.js.map +1 -0
- package/dist/utils/config.d.ts +14 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +34 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/schema.d.ts +273 -0
- package/dist/utils/schema.d.ts.map +1 -0
- package/dist/utils/schema.js +98 -0
- package/dist/utils/schema.js.map +1 -0
- package/package.json +54 -0
- package/remotion.config.ts +4 -0
- package/skills/make-demo/SKILL.md +282 -0
- package/skills/make-demo/references/demo-script-schema.md +47 -0
- package/skills/make-demo/references/render-props-schema.md +49 -0
- package/skills/make-demo/references/toolkit-commands.md +23 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { AbsoluteFill, interpolate, useCurrentFrame, useVideoConfig, } from "remotion";
|
|
3
|
+
export const SceneTransition = ({ type, durationFrames, direction, }) => {
|
|
4
|
+
const frame = useCurrentFrame();
|
|
5
|
+
const { width } = useVideoConfig();
|
|
6
|
+
if (type === "cut" || durationFrames <= 0)
|
|
7
|
+
return null;
|
|
8
|
+
// Progress: 0 = fully transitioned, 1 = fully visible (for "in" direction)
|
|
9
|
+
const progress = interpolate(frame, [0, durationFrames], [0, 1], {
|
|
10
|
+
extrapolateLeft: "clamp",
|
|
11
|
+
extrapolateRight: "clamp",
|
|
12
|
+
});
|
|
13
|
+
const effectiveProgress = direction === "in" ? progress : 1 - progress;
|
|
14
|
+
switch (type) {
|
|
15
|
+
case "fade": {
|
|
16
|
+
// Overlay a black fill that fades out (for entrance)
|
|
17
|
+
const opacity = 1 - effectiveProgress;
|
|
18
|
+
return (_jsx(AbsoluteFill, { style: {
|
|
19
|
+
backgroundColor: "#000",
|
|
20
|
+
opacity,
|
|
21
|
+
} }));
|
|
22
|
+
}
|
|
23
|
+
case "slide": {
|
|
24
|
+
// Scene slides in from the right (for entrance)
|
|
25
|
+
const translateX = interpolate(effectiveProgress, [0, 1], [width, 0]);
|
|
26
|
+
return (_jsx(AbsoluteFill, { style: {
|
|
27
|
+
backgroundColor: "#000",
|
|
28
|
+
transform: `translateX(${-translateX}px)`,
|
|
29
|
+
} }));
|
|
30
|
+
}
|
|
31
|
+
default:
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=SceneTransition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SceneTransition.js","sourceRoot":"","sources":["../../../src/compositor/components/SceneTransition.tsx"],"names":[],"mappings":";AACA,OAAO,EACL,YAAY,EACZ,WAAW,EACX,eAAe,EACf,cAAc,GACf,MAAM,UAAU,CAAC;AAQlB,MAAM,CAAC,MAAM,eAAe,GAAmC,CAAC,EAC9D,IAAI,EACJ,cAAc,EACd,SAAS,GACV,EAAE,EAAE;IACH,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,MAAM,EAAE,KAAK,EAAE,GAAG,cAAc,EAAE,CAAC;IAEnC,IAAI,IAAI,KAAK,KAAK,IAAI,cAAc,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvD,2EAA2E;IAC3E,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;QAC/D,eAAe,EAAE,OAAO;QACxB,gBAAgB,EAAE,OAAO;KAC1B,CAAC,CAAC;IAEH,MAAM,iBAAiB,GAAG,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;IAEvE,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,qDAAqD;YACrD,MAAM,OAAO,GAAG,CAAC,GAAG,iBAAiB,CAAC;YACtC,OAAO,CACL,KAAC,YAAY,IACX,KAAK,EAAE;oBACL,eAAe,EAAE,MAAM;oBACvB,OAAO;iBACR,GACD,CACH,CAAC;QACJ,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,gDAAgD;YAChD,MAAM,UAAU,GAAG,WAAW,CAAC,iBAAiB,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;YACtE,OAAO,CACL,KAAC,YAAY,IACX,KAAK,EAAE;oBACL,eAAe,EAAE,MAAM;oBACvB,SAAS,EAAE,cAAc,CAAC,UAAU,KAAK;iBAC1C,GACD,CACH,CAAC;QACJ,CAAC;QAED;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Subtitles.d.ts","sourceRoot":"","sources":["../../../src/compositor/components/Subtitles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAuE9C,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { interpolate, useCurrentFrame } from "remotion";
|
|
3
|
+
export const Subtitles = ({ text, durationFrames, visible, }) => {
|
|
4
|
+
const frame = useCurrentFrame();
|
|
5
|
+
if (!visible || !text)
|
|
6
|
+
return null;
|
|
7
|
+
const words = text.split(/\s+/);
|
|
8
|
+
const totalWords = words.length;
|
|
9
|
+
// Calculate how many words should be visible at the current frame
|
|
10
|
+
// Leave a small buffer at start and end
|
|
11
|
+
const startFrame = 10;
|
|
12
|
+
const endFrame = durationFrames - 5;
|
|
13
|
+
const visibleWordCount = Math.ceil(interpolate(frame, [startFrame, endFrame], [0, totalWords], {
|
|
14
|
+
extrapolateLeft: "clamp",
|
|
15
|
+
extrapolateRight: "clamp",
|
|
16
|
+
}));
|
|
17
|
+
// Fade in
|
|
18
|
+
const opacity = interpolate(frame, [0, 10], [0, 1], {
|
|
19
|
+
extrapolateLeft: "clamp",
|
|
20
|
+
extrapolateRight: "clamp",
|
|
21
|
+
});
|
|
22
|
+
// Fade out at end
|
|
23
|
+
const fadeOut = interpolate(frame, [durationFrames - 10, durationFrames], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
|
|
24
|
+
return (_jsx("div", { style: {
|
|
25
|
+
position: "absolute",
|
|
26
|
+
bottom: 48,
|
|
27
|
+
left: "50%",
|
|
28
|
+
transform: "translateX(-50%)",
|
|
29
|
+
maxWidth: "80%",
|
|
30
|
+
opacity: opacity * fadeOut,
|
|
31
|
+
}, children: _jsx("div", { style: {
|
|
32
|
+
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
|
33
|
+
borderRadius: 12,
|
|
34
|
+
padding: "12px 24px",
|
|
35
|
+
backdropFilter: "blur(8px)",
|
|
36
|
+
}, children: _jsx("span", { style: {
|
|
37
|
+
color: "#fff",
|
|
38
|
+
fontSize: 24,
|
|
39
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
40
|
+
fontWeight: 500,
|
|
41
|
+
lineHeight: 1.4,
|
|
42
|
+
letterSpacing: 0.3,
|
|
43
|
+
}, children: words.slice(0, visibleWordCount).join(" ") }) }) }));
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=Subtitles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Subtitles.js","sourceRoot":"","sources":["../../../src/compositor/components/Subtitles.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAQxD,MAAM,CAAC,MAAM,SAAS,GAA6B,CAAC,EAClD,IAAI,EACJ,cAAc,EACd,OAAO,GACR,EAAE,EAAE;IACH,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAEhC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;IAEhC,kEAAkE;IAClE,wCAAwC;IACxC,MAAM,UAAU,GAAG,EAAE,CAAC;IACtB,MAAM,QAAQ,GAAG,cAAc,GAAG,CAAC,CAAC;IACpC,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAChC,WAAW,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;QAC1D,eAAe,EAAE,OAAO;QACxB,gBAAgB,EAAE,OAAO;KAC1B,CAAC,CACH,CAAC;IAEF,UAAU;IACV,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;QAClD,eAAe,EAAE,OAAO;QACxB,gBAAgB,EAAE,OAAO;KAC1B,CAAC,CAAC;IAEH,kBAAkB;IAClB,MAAM,OAAO,GAAG,WAAW,CACzB,KAAK,EACL,CAAC,cAAc,GAAG,EAAE,EAAE,cAAc,CAAC,EACrC,CAAC,CAAC,EAAE,CAAC,CAAC,EACN,EAAE,eAAe,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,CACxD,CAAC;IAEF,OAAO,CACL,cACE,KAAK,EAAE;YACL,QAAQ,EAAE,UAAU;YACpB,MAAM,EAAE,EAAE;YACV,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,kBAAkB;YAC7B,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,OAAO,GAAG,OAAO;SAC3B,YAED,cACE,KAAK,EAAE;gBACL,eAAe,EAAE,oBAAoB;gBACrC,YAAY,EAAE,EAAE;gBAChB,OAAO,EAAE,WAAW;gBACpB,cAAc,EAAE,WAAW;aAC5B,YAED,eACE,KAAK,EAAE;oBACL,KAAK,EAAE,MAAM;oBACb,QAAQ,EAAE,EAAE;oBACZ,UAAU,EAAE,sCAAsC;oBAClD,UAAU,EAAE,GAAG;oBACf,UAAU,EAAE,GAAG;oBACf,aAAa,EAAE,GAAG;iBACnB,YAEA,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GACtC,GACH,GACF,CACP,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compositor/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compositor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,YAAY,CAAC,YAAY,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RenderProps, RenderScene } from "../utils/schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Calculate total duration in frames for the entire composition.
|
|
4
|
+
* Accounts for transition overlaps between scenes.
|
|
5
|
+
* Used by calculateMetadata in Root.tsx.
|
|
6
|
+
*/
|
|
7
|
+
export declare function calculateTotalFrames(props: RenderProps): number;
|
|
8
|
+
/**
|
|
9
|
+
* Estimate duration from narration text (~150 words per minute = 2.5 wps).
|
|
10
|
+
*/
|
|
11
|
+
export declare function estimateDuration(narration: string): number;
|
|
12
|
+
/**
|
|
13
|
+
* Get the scene duration in seconds.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getSceneDuration(scene: RenderScene): number;
|
|
16
|
+
//# sourceMappingURL=timing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../../src/compositor/timing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAInE;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAqB/D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAE3D"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const TRANSITION_DURATION_SECONDS = 0.5;
|
|
2
|
+
/**
|
|
3
|
+
* Calculate total duration in frames for the entire composition.
|
|
4
|
+
* Accounts for transition overlaps between scenes.
|
|
5
|
+
* Used by calculateMetadata in Root.tsx.
|
|
6
|
+
*/
|
|
7
|
+
export function calculateTotalFrames(props) {
|
|
8
|
+
const { fps, scenes } = props;
|
|
9
|
+
if (scenes.length === 0)
|
|
10
|
+
return 0;
|
|
11
|
+
const transitionFrames = Math.ceil(TRANSITION_DURATION_SECONDS * fps);
|
|
12
|
+
// Sum all scene durations
|
|
13
|
+
let total = 0;
|
|
14
|
+
for (const scene of scenes) {
|
|
15
|
+
total += Math.ceil(scene.avatarDuration * fps);
|
|
16
|
+
}
|
|
17
|
+
// Subtract transition overlaps between consecutive non-cut scenes
|
|
18
|
+
for (let i = 0; i < scenes.length - 1; i++) {
|
|
19
|
+
const nextScene = scenes[i + 1];
|
|
20
|
+
if (nextScene && nextScene.transition !== "cut") {
|
|
21
|
+
total -= transitionFrames;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return total;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Estimate duration from narration text (~150 words per minute = 2.5 wps).
|
|
28
|
+
*/
|
|
29
|
+
export function estimateDuration(narration) {
|
|
30
|
+
const words = narration.trim().split(/\s+/).length;
|
|
31
|
+
return Math.max(2, words / 2.5);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get the scene duration in seconds.
|
|
35
|
+
*/
|
|
36
|
+
export function getSceneDuration(scene) {
|
|
37
|
+
return scene.avatarDuration;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=timing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timing.js","sourceRoot":"","sources":["../../src/compositor/timing.ts"],"names":[],"mappings":"AAEA,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAExC;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAkB;IACrD,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAC9B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAElC,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,2BAA2B,GAAG,GAAG,CAAC,CAAC;IAEtE,0BAA0B;IAC1B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,GAAG,CAAC,CAAC;IACjD,CAAC;IAED,kEAAkE;IAClE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChC,IAAI,SAAS,IAAI,SAAS,CAAC,UAAU,KAAK,KAAK,EAAE,CAAC;YAChD,KAAK,IAAI,gBAAgB,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;IACnD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,GAAG,CAAC,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAkB;IACjD,OAAO,KAAK,CAAC,cAAc,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface DIDAvatar {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
sentiments: {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
}[];
|
|
8
|
+
}
|
|
9
|
+
export interface CreateVideoOptions {
|
|
10
|
+
avatarId: string;
|
|
11
|
+
sentimentId?: string;
|
|
12
|
+
script: string;
|
|
13
|
+
config?: {
|
|
14
|
+
result_format?: "mp4" | "mov" | "webm";
|
|
15
|
+
output_resolution?: 480 | 720 | 1080;
|
|
16
|
+
};
|
|
17
|
+
background?: {
|
|
18
|
+
type: "color";
|
|
19
|
+
value: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface VideoStatus {
|
|
23
|
+
id: string;
|
|
24
|
+
status: "created" | "started" | "done" | "error" | "rejected";
|
|
25
|
+
result_url?: string;
|
|
26
|
+
duration?: number;
|
|
27
|
+
error?: {
|
|
28
|
+
kind: string;
|
|
29
|
+
description: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface PollOptions {
|
|
33
|
+
interval?: number;
|
|
34
|
+
timeout?: number;
|
|
35
|
+
}
|
|
36
|
+
export declare class DIDClient {
|
|
37
|
+
private apiKey;
|
|
38
|
+
constructor(apiKey: string);
|
|
39
|
+
private get headers();
|
|
40
|
+
private request;
|
|
41
|
+
listAvatars(): Promise<DIDAvatar[]>;
|
|
42
|
+
createVideo(options: CreateVideoOptions): Promise<{
|
|
43
|
+
id: string;
|
|
44
|
+
status: string;
|
|
45
|
+
}>;
|
|
46
|
+
getVideo(id: string): Promise<VideoStatus>;
|
|
47
|
+
pollUntilDone(id: string, options?: PollOptions): Promise<VideoStatus>;
|
|
48
|
+
downloadVideo(resultUrl: string, outputPath: string): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/d-id/client.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE;QACP,aAAa,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;QACvC,iBAAiB,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;KACtC,CAAC;IACF,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,OAAO,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAI1B,OAAO,KAAK,OAAO,GAKlB;YAEa,OAAO;IAiEf,WAAW,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAQnC,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAsBjF,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAI1C,aAAa,CACjB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,WAAW,CAAC;IA4BjB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAY1E"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { createWriteStream } from "node:fs";
|
|
2
|
+
import { pipeline } from "node:stream/promises";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
const BASE_URL = "https://api.d-id.com";
|
|
5
|
+
export class DIDClient {
|
|
6
|
+
apiKey;
|
|
7
|
+
constructor(apiKey) {
|
|
8
|
+
this.apiKey = apiKey;
|
|
9
|
+
}
|
|
10
|
+
get headers() {
|
|
11
|
+
return {
|
|
12
|
+
Authorization: `Basic ${this.apiKey}`,
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async request(method, path, body, retries = 3) {
|
|
17
|
+
let lastError = null;
|
|
18
|
+
for (let attempt = 0; attempt < retries; attempt++) {
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(`${BASE_URL}${path}`, {
|
|
21
|
+
method,
|
|
22
|
+
headers: this.headers,
|
|
23
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
24
|
+
});
|
|
25
|
+
if (response.ok) {
|
|
26
|
+
return (await response.json());
|
|
27
|
+
}
|
|
28
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
29
|
+
if (response.status === 401) {
|
|
30
|
+
throw new Error("D-ID authentication failed (401). Check your DID_API_KEY.");
|
|
31
|
+
}
|
|
32
|
+
if (response.status === 402) {
|
|
33
|
+
throw new Error("D-ID insufficient credits (402). Top up your D-ID account to continue.");
|
|
34
|
+
}
|
|
35
|
+
// Don't retry client errors (4xx) other than rate limits
|
|
36
|
+
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
|
|
37
|
+
throw new Error(`D-ID API error ${response.status}: ${errorBody.description || JSON.stringify(errorBody)}`);
|
|
38
|
+
}
|
|
39
|
+
lastError = new Error(`D-ID API error ${response.status}: ${errorBody.description || "unknown error"}`);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
if (err instanceof Error &&
|
|
43
|
+
(err.message.includes("401") ||
|
|
44
|
+
err.message.includes("402") ||
|
|
45
|
+
err.message.includes("D-ID API error 4"))) {
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
lastError = err;
|
|
49
|
+
}
|
|
50
|
+
// Exponential backoff before retry
|
|
51
|
+
if (attempt < retries - 1) {
|
|
52
|
+
const delay = Math.pow(2, attempt) * 1000;
|
|
53
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw lastError ?? new Error("D-ID API request failed after retries");
|
|
57
|
+
}
|
|
58
|
+
async listAvatars() {
|
|
59
|
+
const data = await this.request("GET", "/expressives/avatars");
|
|
60
|
+
return data.avatars ?? data;
|
|
61
|
+
}
|
|
62
|
+
async createVideo(options) {
|
|
63
|
+
const body = {
|
|
64
|
+
avatar_id: options.avatarId,
|
|
65
|
+
script: {
|
|
66
|
+
type: "text",
|
|
67
|
+
input: options.script,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
if (options.sentimentId) {
|
|
71
|
+
body.sentiment_id = options.sentimentId;
|
|
72
|
+
}
|
|
73
|
+
if (options.config) {
|
|
74
|
+
body.config = options.config;
|
|
75
|
+
}
|
|
76
|
+
if (options.background) {
|
|
77
|
+
body.background = options.background;
|
|
78
|
+
}
|
|
79
|
+
return this.request("POST", "/expressives", body);
|
|
80
|
+
}
|
|
81
|
+
async getVideo(id) {
|
|
82
|
+
return this.request("GET", `/expressives/${id}`, undefined, 1);
|
|
83
|
+
}
|
|
84
|
+
async pollUntilDone(id, options = {}) {
|
|
85
|
+
const interval = options.interval ?? 5000;
|
|
86
|
+
const timeout = options.timeout ?? 600000; // 10 minutes
|
|
87
|
+
const startTime = Date.now();
|
|
88
|
+
while (true) {
|
|
89
|
+
const video = await this.getVideo(id);
|
|
90
|
+
if (video.status === "done") {
|
|
91
|
+
return video;
|
|
92
|
+
}
|
|
93
|
+
if (video.status === "error" || video.status === "rejected") {
|
|
94
|
+
throw new Error(`D-ID video generation failed: ${video.error?.description ?? video.status}`);
|
|
95
|
+
}
|
|
96
|
+
if (Date.now() - startTime > timeout) {
|
|
97
|
+
throw new Error(`D-ID video generation timed out after ${timeout / 1000}s (status: ${video.status})`);
|
|
98
|
+
}
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async downloadVideo(resultUrl, outputPath) {
|
|
103
|
+
const response = await fetch(resultUrl);
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
throw new Error(`Failed to download video: HTTP ${response.status}`);
|
|
106
|
+
}
|
|
107
|
+
if (!response.body) {
|
|
108
|
+
throw new Error("Response body is empty");
|
|
109
|
+
}
|
|
110
|
+
const fileStream = createWriteStream(outputPath);
|
|
111
|
+
await pipeline(Readable.fromWeb(response.body), fileStream);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/d-id/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface GenerateOptions {
|
|
2
|
+
scriptPath: string;
|
|
3
|
+
outputDir: string;
|
|
4
|
+
defaultAvatarId?: string;
|
|
5
|
+
defaultSentimentId?: string;
|
|
6
|
+
concurrency: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function generateAvatarClips(options: GenerateOptions): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=generate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/d-id/generate.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AAeD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAqGjF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolve, join } from "node:path";
|
|
3
|
+
import { DIDClient } from "./client.js";
|
|
4
|
+
import { requireDidApiKey } from "../utils/config.js";
|
|
5
|
+
export async function generateAvatarClips(options) {
|
|
6
|
+
const apiKey = requireDidApiKey();
|
|
7
|
+
const client = new DIDClient(apiKey);
|
|
8
|
+
// Read and parse script
|
|
9
|
+
const scriptPath = resolve(options.scriptPath);
|
|
10
|
+
const raw = readFileSync(scriptPath, "utf-8");
|
|
11
|
+
const scenes = JSON.parse(raw);
|
|
12
|
+
if (!Array.isArray(scenes) || scenes.length === 0) {
|
|
13
|
+
throw new Error("Script must be a non-empty array of scenes with { id, narration }");
|
|
14
|
+
}
|
|
15
|
+
// Ensure output directory exists
|
|
16
|
+
const outputDir = resolve(options.outputDir);
|
|
17
|
+
mkdirSync(outputDir, { recursive: true });
|
|
18
|
+
const total = scenes.length;
|
|
19
|
+
const manifest = [];
|
|
20
|
+
let completed = 0;
|
|
21
|
+
console.log(`\nGenerating ${total} avatar clip(s)...\n`);
|
|
22
|
+
// Process scenes with concurrency limit
|
|
23
|
+
const queue = [...scenes];
|
|
24
|
+
const inFlight = [];
|
|
25
|
+
async function processScene(scene) {
|
|
26
|
+
const avatarId = scene.avatarId ?? options.defaultAvatarId;
|
|
27
|
+
if (!avatarId) {
|
|
28
|
+
throw new Error(`No avatar ID for scene "${scene.id}". Provide --avatar or set avatarId per scene.`);
|
|
29
|
+
}
|
|
30
|
+
const sentimentId = scene.sentimentId ?? options.defaultSentimentId;
|
|
31
|
+
console.log(` [${completed + 1}/${total}] Generating avatar for "${scene.id}"...`);
|
|
32
|
+
// Rate limit: minimum 500ms between API calls
|
|
33
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
34
|
+
// Create the video
|
|
35
|
+
const created = await client.createVideo({
|
|
36
|
+
avatarId,
|
|
37
|
+
sentimentId,
|
|
38
|
+
script: scene.narration,
|
|
39
|
+
config: { result_format: "mp4", output_resolution: 1080 },
|
|
40
|
+
background: { type: "color", value: "#1a1a1a" },
|
|
41
|
+
});
|
|
42
|
+
// Poll until done
|
|
43
|
+
const result = await client.pollUntilDone(created.id, {
|
|
44
|
+
interval: 5000,
|
|
45
|
+
timeout: 600000,
|
|
46
|
+
});
|
|
47
|
+
if (!result.result_url) {
|
|
48
|
+
throw new Error(`No result URL for scene "${scene.id}" (id: ${created.id})`);
|
|
49
|
+
}
|
|
50
|
+
// Download the clip
|
|
51
|
+
const clipPath = join(outputDir, `${scene.id}.mp4`);
|
|
52
|
+
await client.downloadVideo(result.result_url, clipPath);
|
|
53
|
+
completed++;
|
|
54
|
+
console.log(` [${completed}/${total}] Done: ${scene.id} (${result.duration ?? "?"}s)`);
|
|
55
|
+
manifest.push({
|
|
56
|
+
id: scene.id,
|
|
57
|
+
clipPath,
|
|
58
|
+
duration: result.duration ?? 0,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// Run with concurrency limit
|
|
62
|
+
for (const scene of queue) {
|
|
63
|
+
const promise = processScene(scene).then(() => {
|
|
64
|
+
const idx = inFlight.indexOf(promise);
|
|
65
|
+
if (idx !== -1)
|
|
66
|
+
inFlight.splice(idx, 1);
|
|
67
|
+
});
|
|
68
|
+
inFlight.push(promise);
|
|
69
|
+
if (inFlight.length >= options.concurrency) {
|
|
70
|
+
await Promise.race(inFlight);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Wait for remaining
|
|
74
|
+
await Promise.all(inFlight);
|
|
75
|
+
// Write manifest
|
|
76
|
+
const manifestPath = join(outputDir, "manifest.json");
|
|
77
|
+
writeFileSync(manifestPath, JSON.stringify({ scenes: manifest }, null, 2), "utf-8");
|
|
78
|
+
console.log(`\nAll ${total} clip(s) generated.`);
|
|
79
|
+
console.log(`Manifest: ${manifestPath}\n`);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/d-id/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAuBtD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAwB;IAChE,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;IAErC,wBAAwB;IACxB,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAiB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAE7C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IAED,iCAAiC;IACjC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC7C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5B,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,sBAAsB,CAAC,CAAC;IAEzD,wCAAwC;IACxC,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAC1B,MAAM,QAAQ,GAAoB,EAAE,CAAC;IAErC,KAAK,UAAU,YAAY,CAAC,KAAiB;QAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC;QAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,2BAA2B,KAAK,CAAC,EAAE,gDAAgD,CACpF,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,OAAO,CAAC,kBAAkB,CAAC;QAEpE,OAAO,CAAC,GAAG,CAAC,MAAM,SAAS,GAAG,CAAC,IAAI,KAAK,4BAA4B,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;QAEpF,8CAA8C;QAC9C,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QAEzD,mBAAmB;QACnB,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;YACvC,QAAQ;YACR,WAAW;YACX,MAAM,EAAE,KAAK,CAAC,SAAS;YACvB,MAAM,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;YACzD,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE;SAChD,CAAC,CAAC;QAEH,kBAAkB;QAClB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE;YACpD,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,CAAC,EAAE,UAAU,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;QAC/E,CAAC;QAED,oBAAoB;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAExD,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,MAAM,SAAS,IAAI,KAAK,WAAW,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC,QAAQ,IAAI,GAAG,IAAI,CAAC,CAAC;QAExF,QAAQ,CAAC,IAAI,CAAC;YACZ,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,QAAQ;YACR,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,6BAA6B;IAC7B,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;YAC5C,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACtC,IAAI,GAAG,KAAK,CAAC,CAAC;gBAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEvB,IAAI,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAE5B,iBAAiB;IACjB,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;IACtD,aAAa,CACX,YAAY,EACZ,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAC7C,OAAO,CACR,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,qBAAqB,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,aAAa,YAAY,IAAI,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ToolkitConfig {
|
|
2
|
+
didApiKey: string | undefined;
|
|
3
|
+
browserUseApiKey: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Loads configuration from environment variables, falling back to .env.local
|
|
7
|
+
* in the current working directory.
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadConfig(): ToolkitConfig;
|
|
10
|
+
/**
|
|
11
|
+
* Returns the D-ID API key or throws with a helpful error message.
|
|
12
|
+
*/
|
|
13
|
+
export declare function requireDidApiKey(): string;
|
|
14
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,aAAa,CAiB1C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAQzC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as dotenv from "dotenv";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* Loads configuration from environment variables, falling back to .env.local
|
|
6
|
+
* in the current working directory.
|
|
7
|
+
*/
|
|
8
|
+
export function loadConfig() {
|
|
9
|
+
// Try loading .env.local from the user's project directory
|
|
10
|
+
const envLocalPath = resolve(process.cwd(), ".env.local");
|
|
11
|
+
if (existsSync(envLocalPath)) {
|
|
12
|
+
dotenv.config({ path: envLocalPath });
|
|
13
|
+
}
|
|
14
|
+
// Also try .env as a fallback
|
|
15
|
+
const envPath = resolve(process.cwd(), ".env");
|
|
16
|
+
if (existsSync(envPath)) {
|
|
17
|
+
dotenv.config({ path: envPath });
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
didApiKey: process.env.DID_API_KEY,
|
|
21
|
+
browserUseApiKey: process.env.BROWSER_USE_API_KEY,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Returns the D-ID API key or throws with a helpful error message.
|
|
26
|
+
*/
|
|
27
|
+
export function requireDidApiKey() {
|
|
28
|
+
const config = loadConfig();
|
|
29
|
+
if (!config.didApiKey) {
|
|
30
|
+
throw new Error("DID_API_KEY not found. Set it as an environment variable or in your project's .env.local file.");
|
|
31
|
+
}
|
|
32
|
+
return config.didApiKey;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC;;;GAGG;AACH,MAAM,UAAU,UAAU;IACxB,2DAA2D;IAC3D,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,YAAY,CAAC,CAAC;IAC1D,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,8BAA8B;IAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;IAC/C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,OAAO;QACL,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;QAClC,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB;KAClD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,gGAAgG,CACjG,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,SAAS,CAAC;AAC1B,CAAC"}
|