@juspay/neurolink 9.64.0 → 9.65.1
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/CHANGELOG.md +12 -0
- package/README.md +18 -17
- package/dist/adapters/providerImageAdapter.js +29 -1
- package/dist/adapters/replicate/auth.d.ts +19 -0
- package/dist/adapters/replicate/auth.js +32 -0
- package/dist/adapters/replicate/predictionLifecycle.d.ts +46 -0
- package/dist/adapters/replicate/predictionLifecycle.js +283 -0
- package/dist/adapters/video/klingVideoHandler.d.ts +37 -0
- package/dist/adapters/video/klingVideoHandler.js +305 -0
- package/dist/adapters/video/replicateVideoHandler.d.ts +29 -0
- package/dist/adapters/video/replicateVideoHandler.js +157 -0
- package/dist/adapters/video/runwayVideoHandler.d.ts +32 -0
- package/dist/adapters/video/runwayVideoHandler.js +316 -0
- package/dist/adapters/video/vertexVideoHandler.d.ts +19 -1
- package/dist/adapters/video/vertexVideoHandler.js +33 -9
- package/dist/agent/directTools.js +11 -3
- package/dist/autoresearch/runner.js +8 -2
- package/dist/avatar/index.d.ts +13 -0
- package/dist/avatar/index.js +13 -0
- package/dist/avatar/providers/DIDAvatar.d.ts +49 -0
- package/dist/avatar/providers/DIDAvatar.js +501 -0
- package/dist/avatar/providers/HeyGenAvatar.d.ts +30 -0
- package/dist/avatar/providers/HeyGenAvatar.js +337 -0
- package/dist/avatar/providers/ReplicateAvatar.d.ts +36 -0
- package/dist/avatar/providers/ReplicateAvatar.js +267 -0
- package/dist/browser/neurolink.min.js +624 -601
- package/dist/cli/commands/mcp.js +29 -0
- package/dist/cli/commands/proxy.js +24 -5
- package/dist/cli/factories/commandFactory.d.ts +11 -1
- package/dist/cli/factories/commandFactory.js +291 -38
- package/dist/constants/contextWindows.js +101 -0
- package/dist/constants/enums.d.ts +273 -2
- package/dist/constants/enums.js +290 -1
- package/dist/constants/videoErrors.d.ts +4 -0
- package/dist/constants/videoErrors.js +4 -0
- package/dist/core/baseProvider.d.ts +22 -2
- package/dist/core/baseProvider.js +217 -11
- package/dist/core/constants.d.ts +12 -0
- package/dist/core/constants.js +72 -1
- package/dist/evaluation/index.d.ts +2 -0
- package/dist/evaluation/index.js +4 -0
- package/dist/factories/providerFactory.js +7 -1
- package/dist/factories/providerRegistry.js +202 -5
- package/dist/features/ppt/contentPlanner.js +42 -14
- package/dist/index.d.ts +9 -1
- package/dist/index.js +16 -1
- package/dist/lib/adapters/providerImageAdapter.js +29 -1
- package/dist/lib/adapters/replicate/auth.d.ts +19 -0
- package/dist/lib/adapters/replicate/auth.js +33 -0
- package/dist/lib/adapters/replicate/predictionLifecycle.d.ts +46 -0
- package/dist/lib/adapters/replicate/predictionLifecycle.js +284 -0
- package/dist/lib/adapters/video/klingVideoHandler.d.ts +37 -0
- package/dist/lib/adapters/video/klingVideoHandler.js +306 -0
- package/dist/lib/adapters/video/replicateVideoHandler.d.ts +29 -0
- package/dist/lib/adapters/video/replicateVideoHandler.js +158 -0
- package/dist/lib/adapters/video/runwayVideoHandler.d.ts +32 -0
- package/dist/lib/adapters/video/runwayVideoHandler.js +317 -0
- package/dist/lib/adapters/video/vertexVideoHandler.d.ts +19 -1
- package/dist/lib/adapters/video/vertexVideoHandler.js +33 -9
- package/dist/lib/agent/directTools.js +11 -3
- package/dist/lib/autoresearch/runner.js +8 -2
- package/dist/lib/avatar/index.d.ts +13 -0
- package/dist/lib/avatar/index.js +14 -0
- package/dist/lib/avatar/providers/DIDAvatar.d.ts +49 -0
- package/dist/lib/avatar/providers/DIDAvatar.js +502 -0
- package/dist/lib/avatar/providers/HeyGenAvatar.d.ts +30 -0
- package/dist/lib/avatar/providers/HeyGenAvatar.js +338 -0
- package/dist/lib/avatar/providers/ReplicateAvatar.d.ts +36 -0
- package/dist/lib/avatar/providers/ReplicateAvatar.js +268 -0
- package/dist/lib/constants/contextWindows.js +101 -0
- package/dist/lib/constants/enums.d.ts +273 -2
- package/dist/lib/constants/enums.js +290 -1
- package/dist/lib/constants/videoErrors.d.ts +4 -0
- package/dist/lib/constants/videoErrors.js +4 -0
- package/dist/lib/core/baseProvider.d.ts +22 -2
- package/dist/lib/core/baseProvider.js +217 -11
- package/dist/lib/core/constants.d.ts +12 -0
- package/dist/lib/core/constants.js +72 -1
- package/dist/lib/evaluation/index.d.ts +2 -0
- package/dist/lib/evaluation/index.js +4 -0
- package/dist/lib/factories/providerFactory.js +7 -1
- package/dist/lib/factories/providerRegistry.js +202 -5
- package/dist/lib/features/ppt/contentPlanner.js +42 -14
- package/dist/lib/index.d.ts +9 -1
- package/dist/lib/index.js +16 -1
- package/dist/lib/middleware/builtin/lifecycle.js +39 -9
- package/dist/lib/music/index.d.ts +13 -0
- package/dist/lib/music/index.js +14 -0
- package/dist/lib/music/providers/BeatovenMusic.d.ts +31 -0
- package/dist/lib/music/providers/BeatovenMusic.js +334 -0
- package/dist/lib/music/providers/ElevenLabsMusic.d.ts +30 -0
- package/dist/lib/music/providers/ElevenLabsMusic.js +169 -0
- package/dist/lib/music/providers/LyriaMusic.d.ts +29 -0
- package/dist/lib/music/providers/LyriaMusic.js +173 -0
- package/dist/lib/music/providers/ReplicateMusic.d.ts +31 -0
- package/dist/lib/music/providers/ReplicateMusic.js +262 -0
- package/dist/lib/neurolink.d.ts +30 -0
- package/dist/lib/neurolink.js +323 -77
- package/dist/lib/providers/amazonBedrock.d.ts +10 -0
- package/dist/lib/providers/amazonBedrock.js +94 -39
- package/dist/lib/providers/anthropic.js +55 -7
- package/dist/lib/providers/anthropicBaseProvider.js +1 -1
- package/dist/lib/providers/azureOpenai.js +66 -17
- package/dist/lib/providers/cloudflare.d.ts +35 -0
- package/dist/lib/providers/cloudflare.js +174 -0
- package/dist/lib/providers/cohere.d.ts +52 -0
- package/dist/lib/providers/cohere.js +253 -0
- package/dist/lib/providers/deepseek.js +72 -17
- package/dist/lib/providers/fireworks.d.ts +33 -0
- package/dist/lib/providers/fireworks.js +164 -0
- package/dist/lib/providers/googleAiStudio.js +126 -10
- package/dist/lib/providers/googleNativeGemini3.d.ts +26 -6
- package/dist/lib/providers/googleNativeGemini3.js +276 -29
- package/dist/lib/providers/googleVertex.js +639 -181
- package/dist/lib/providers/groq.d.ts +33 -0
- package/dist/lib/providers/groq.js +181 -0
- package/dist/lib/providers/huggingFace.js +9 -8
- package/dist/lib/providers/ideogram.d.ts +34 -0
- package/dist/lib/providers/ideogram.js +184 -0
- package/dist/lib/providers/index.d.ts +13 -0
- package/dist/lib/providers/index.js +13 -0
- package/dist/lib/providers/jina.d.ts +59 -0
- package/dist/lib/providers/jina.js +218 -0
- package/dist/lib/providers/llamaCpp.js +14 -46
- package/dist/lib/providers/lmStudio.js +14 -47
- package/dist/lib/providers/mistral.js +7 -7
- package/dist/lib/providers/nvidiaNim.js +160 -19
- package/dist/lib/providers/ollama.js +7 -7
- package/dist/lib/providers/openAI.d.ts +22 -1
- package/dist/lib/providers/openAI.js +181 -0
- package/dist/lib/providers/openRouter.js +35 -23
- package/dist/lib/providers/openaiCompatible.js +9 -8
- package/dist/lib/providers/perplexity.d.ts +33 -0
- package/dist/lib/providers/perplexity.js +179 -0
- package/dist/lib/providers/recraft.d.ts +34 -0
- package/dist/lib/providers/recraft.js +197 -0
- package/dist/lib/providers/replicate.d.ts +75 -0
- package/dist/lib/providers/replicate.js +403 -0
- package/dist/lib/providers/stability.d.ts +37 -0
- package/dist/lib/providers/stability.js +191 -0
- package/dist/lib/providers/togetherAi.d.ts +33 -0
- package/dist/lib/providers/togetherAi.js +176 -0
- package/dist/lib/providers/voyage.d.ts +47 -0
- package/dist/lib/providers/voyage.js +177 -0
- package/dist/lib/providers/xai.d.ts +33 -0
- package/dist/lib/providers/xai.js +172 -0
- package/dist/lib/telemetry/index.d.ts +1 -1
- package/dist/lib/telemetry/index.js +1 -1
- package/dist/lib/telemetry/tracers.d.ts +19 -0
- package/dist/lib/telemetry/tracers.js +19 -0
- package/dist/lib/telemetry/withSpan.d.ts +35 -0
- package/dist/lib/telemetry/withSpan.js +103 -0
- package/dist/lib/types/avatar.d.ts +143 -0
- package/dist/lib/types/avatar.js +20 -0
- package/dist/lib/types/cli.d.ts +6 -0
- package/dist/lib/types/conversation.d.ts +16 -0
- package/dist/lib/types/generate.d.ts +62 -5
- package/dist/lib/types/index.d.ts +5 -0
- package/dist/lib/types/index.js +7 -0
- package/dist/lib/types/middleware.d.ts +27 -0
- package/dist/lib/types/multimodal.d.ts +35 -2
- package/dist/lib/types/music.d.ts +165 -0
- package/dist/lib/types/music.js +21 -0
- package/dist/lib/types/providers.d.ts +144 -1
- package/dist/lib/types/replicate.d.ts +67 -0
- package/dist/lib/types/replicate.js +10 -0
- package/dist/lib/types/safeFetch.d.ts +15 -0
- package/dist/lib/types/safeFetch.js +7 -0
- package/dist/lib/types/stream.d.ts +2 -1
- package/dist/lib/types/tools.d.ts +13 -0
- package/dist/lib/types/video.d.ts +89 -0
- package/dist/lib/types/video.js +15 -0
- package/dist/lib/utils/avatarProcessor.d.ts +68 -0
- package/dist/lib/utils/avatarProcessor.js +172 -0
- package/dist/lib/utils/cloneOptions.d.ts +36 -0
- package/dist/lib/utils/cloneOptions.js +62 -0
- package/dist/lib/utils/lifecycleCallbacks.d.ts +51 -8
- package/dist/lib/utils/lifecycleCallbacks.js +82 -26
- package/dist/lib/utils/lifecycleTimeout.d.ts +25 -0
- package/dist/lib/utils/lifecycleTimeout.js +39 -0
- package/dist/lib/utils/logSanitize.d.ts +49 -0
- package/dist/lib/utils/logSanitize.js +170 -0
- package/dist/lib/utils/loggingFetch.d.ts +29 -0
- package/dist/lib/utils/loggingFetch.js +60 -0
- package/dist/lib/utils/messageBuilder.js +43 -25
- package/dist/lib/utils/modelChoices.js +236 -3
- package/dist/lib/utils/musicProcessor.d.ts +67 -0
- package/dist/lib/utils/musicProcessor.js +189 -0
- package/dist/lib/utils/optionsConversion.js +3 -2
- package/dist/lib/utils/parameterValidation.js +14 -4
- package/dist/lib/utils/pricing.js +193 -0
- package/dist/lib/utils/providerConfig.d.ts +55 -0
- package/dist/lib/utils/providerConfig.js +224 -0
- package/dist/lib/utils/safeFetch.d.ts +26 -0
- package/dist/lib/utils/safeFetch.js +83 -0
- package/dist/lib/utils/sizeGuard.d.ts +34 -0
- package/dist/lib/utils/sizeGuard.js +45 -0
- package/dist/lib/utils/ssrfGuard.d.ts +52 -0
- package/dist/lib/utils/ssrfGuard.js +411 -0
- package/dist/lib/utils/videoProcessor.d.ts +60 -0
- package/dist/lib/utils/videoProcessor.js +201 -0
- package/dist/lib/voice/providers/FishAudioTTS.d.ts +27 -0
- package/dist/lib/voice/providers/FishAudioTTS.js +183 -0
- package/dist/lib/workflow/core/ensembleExecutor.js +26 -9
- package/dist/middleware/builtin/lifecycle.js +39 -9
- package/dist/music/index.d.ts +13 -0
- package/dist/music/index.js +13 -0
- package/dist/music/providers/BeatovenMusic.d.ts +31 -0
- package/dist/music/providers/BeatovenMusic.js +333 -0
- package/dist/music/providers/ElevenLabsMusic.d.ts +30 -0
- package/dist/music/providers/ElevenLabsMusic.js +168 -0
- package/dist/music/providers/LyriaMusic.d.ts +29 -0
- package/dist/music/providers/LyriaMusic.js +172 -0
- package/dist/music/providers/ReplicateMusic.d.ts +31 -0
- package/dist/music/providers/ReplicateMusic.js +261 -0
- package/dist/neurolink.d.ts +30 -0
- package/dist/neurolink.js +323 -77
- package/dist/providers/amazonBedrock.d.ts +10 -0
- package/dist/providers/amazonBedrock.js +94 -39
- package/dist/providers/anthropic.js +55 -7
- package/dist/providers/anthropicBaseProvider.js +1 -1
- package/dist/providers/azureOpenai.js +66 -17
- package/dist/providers/cloudflare.d.ts +35 -0
- package/dist/providers/cloudflare.js +173 -0
- package/dist/providers/cohere.d.ts +52 -0
- package/dist/providers/cohere.js +252 -0
- package/dist/providers/deepseek.js +72 -17
- package/dist/providers/fireworks.d.ts +33 -0
- package/dist/providers/fireworks.js +163 -0
- package/dist/providers/googleAiStudio.js +126 -10
- package/dist/providers/googleNativeGemini3.d.ts +26 -6
- package/dist/providers/googleNativeGemini3.js +276 -29
- package/dist/providers/googleVertex.js +639 -181
- package/dist/providers/groq.d.ts +33 -0
- package/dist/providers/groq.js +180 -0
- package/dist/providers/huggingFace.js +9 -8
- package/dist/providers/ideogram.d.ts +34 -0
- package/dist/providers/ideogram.js +183 -0
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.js +13 -0
- package/dist/providers/jina.d.ts +59 -0
- package/dist/providers/jina.js +217 -0
- package/dist/providers/llamaCpp.js +14 -46
- package/dist/providers/lmStudio.js +14 -47
- package/dist/providers/mistral.js +7 -7
- package/dist/providers/nvidiaNim.js +160 -19
- package/dist/providers/ollama.js +7 -7
- package/dist/providers/openAI.d.ts +22 -1
- package/dist/providers/openAI.js +181 -0
- package/dist/providers/openRouter.js +35 -23
- package/dist/providers/openaiCompatible.js +9 -8
- package/dist/providers/perplexity.d.ts +33 -0
- package/dist/providers/perplexity.js +178 -0
- package/dist/providers/recraft.d.ts +34 -0
- package/dist/providers/recraft.js +196 -0
- package/dist/providers/replicate.d.ts +75 -0
- package/dist/providers/replicate.js +402 -0
- package/dist/providers/stability.d.ts +37 -0
- package/dist/providers/stability.js +190 -0
- package/dist/providers/togetherAi.d.ts +33 -0
- package/dist/providers/togetherAi.js +175 -0
- package/dist/providers/voyage.d.ts +47 -0
- package/dist/providers/voyage.js +176 -0
- package/dist/providers/xai.d.ts +33 -0
- package/dist/providers/xai.js +171 -0
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/telemetry/index.js +1 -1
- package/dist/telemetry/tracers.d.ts +19 -0
- package/dist/telemetry/tracers.js +19 -0
- package/dist/telemetry/withSpan.d.ts +35 -0
- package/dist/telemetry/withSpan.js +103 -0
- package/dist/types/avatar.d.ts +143 -0
- package/dist/types/avatar.js +19 -0
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/conversation.d.ts +16 -0
- package/dist/types/generate.d.ts +62 -5
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +7 -0
- package/dist/types/middleware.d.ts +27 -0
- package/dist/types/multimodal.d.ts +35 -2
- package/dist/types/music.d.ts +165 -0
- package/dist/types/music.js +20 -0
- package/dist/types/providers.d.ts +144 -1
- package/dist/types/replicate.d.ts +67 -0
- package/dist/types/replicate.js +9 -0
- package/dist/types/safeFetch.d.ts +15 -0
- package/dist/types/safeFetch.js +6 -0
- package/dist/types/stream.d.ts +2 -1
- package/dist/types/tools.d.ts +13 -0
- package/dist/types/video.d.ts +89 -0
- package/dist/types/video.js +14 -0
- package/dist/utils/avatarProcessor.d.ts +68 -0
- package/dist/utils/avatarProcessor.js +171 -0
- package/dist/utils/cloneOptions.d.ts +36 -0
- package/dist/utils/cloneOptions.js +61 -0
- package/dist/utils/lifecycleCallbacks.d.ts +51 -8
- package/dist/utils/lifecycleCallbacks.js +82 -26
- package/dist/utils/lifecycleTimeout.d.ts +25 -0
- package/dist/utils/lifecycleTimeout.js +38 -0
- package/dist/utils/logSanitize.d.ts +49 -0
- package/dist/utils/logSanitize.js +169 -0
- package/dist/utils/loggingFetch.d.ts +29 -0
- package/dist/utils/loggingFetch.js +59 -0
- package/dist/utils/messageBuilder.js +43 -25
- package/dist/utils/modelChoices.js +236 -3
- package/dist/utils/musicProcessor.d.ts +67 -0
- package/dist/utils/musicProcessor.js +188 -0
- package/dist/utils/optionsConversion.js +3 -2
- package/dist/utils/parameterValidation.js +14 -4
- package/dist/utils/pricing.js +193 -0
- package/dist/utils/providerConfig.d.ts +55 -0
- package/dist/utils/providerConfig.js +224 -0
- package/dist/utils/safeFetch.d.ts +26 -0
- package/dist/utils/safeFetch.js +82 -0
- package/dist/utils/sizeGuard.d.ts +34 -0
- package/dist/utils/sizeGuard.js +44 -0
- package/dist/utils/ssrfGuard.d.ts +52 -0
- package/dist/utils/ssrfGuard.js +410 -0
- package/dist/utils/videoProcessor.d.ts +60 -0
- package/dist/utils/videoProcessor.js +200 -0
- package/dist/voice/providers/FishAudioTTS.d.ts +27 -0
- package/dist/voice/providers/FishAudioTTS.js +182 -0
- package/dist/workflow/core/ensembleExecutor.js +26 -9
- package/package.json +32 -5
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D-ID Avatar / Lip-sync Handler
|
|
3
|
+
*
|
|
4
|
+
* Async talking-head generation. Submits a /talks request with a source
|
|
5
|
+
* image and either an audio URL or a text+voice script, polls the talk
|
|
6
|
+
* status, and downloads the resulting MP4.
|
|
7
|
+
*
|
|
8
|
+
* @module avatar/providers/DIDAvatar
|
|
9
|
+
* @see https://docs.d-id.com/reference/talks-overview
|
|
10
|
+
*/
|
|
11
|
+
import { ErrorCategory, ErrorSeverity } from "../../constants/enums.js";
|
|
12
|
+
import { logger } from "../../utils/logger.js";
|
|
13
|
+
import { sanitizeForLog } from "../../utils/logSanitize.js";
|
|
14
|
+
import { AVATAR_ERROR_CODES, AvatarError, } from "../../utils/avatarProcessor.js";
|
|
15
|
+
import { assertSafeUrl } from "../../utils/ssrfGuard.js";
|
|
16
|
+
import { MAX_AUDIO_BYTES, MAX_IMAGE_BYTES, MAX_VIDEO_BYTES, readBoundedBuffer, } from "../../utils/sizeGuard.js";
|
|
17
|
+
const DEFAULT_BASE_URL = "https://api.d-id.com";
|
|
18
|
+
const REQUEST_TIMEOUT_MS = 30_000;
|
|
19
|
+
const POLL_INTERVAL_MS = 3_000;
|
|
20
|
+
const TOTAL_TIMEOUT_MS = 5 * 60_000;
|
|
21
|
+
/**
|
|
22
|
+
* D-ID Avatar Handler.
|
|
23
|
+
*
|
|
24
|
+
* Auth: `Authorization: Basic ${DID_API_KEY}` (the API key is
|
|
25
|
+
* already a base64-encoded `username:password` from the D-ID console).
|
|
26
|
+
*
|
|
27
|
+
* Env vars: `DID_API_KEY` (preferred) / `D_ID_API_KEY` (legacy alias).
|
|
28
|
+
*/
|
|
29
|
+
export class DIDAvatar {
|
|
30
|
+
maxAudioDurationSeconds = 60;
|
|
31
|
+
supportedFormats = ["mp4"];
|
|
32
|
+
apiKey;
|
|
33
|
+
baseUrl;
|
|
34
|
+
constructor(apiKey) {
|
|
35
|
+
const resolved = (apiKey ??
|
|
36
|
+
process.env.DID_API_KEY ??
|
|
37
|
+
process.env.D_ID_API_KEY ??
|
|
38
|
+
"").trim();
|
|
39
|
+
this.apiKey = resolved.length > 0 ? resolved : null;
|
|
40
|
+
this.baseUrl = (process.env.DID_BASE_URL ??
|
|
41
|
+
process.env.D_ID_BASE_URL ??
|
|
42
|
+
DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
43
|
+
}
|
|
44
|
+
isConfigured() {
|
|
45
|
+
return this.apiKey !== null;
|
|
46
|
+
}
|
|
47
|
+
async generate(options) {
|
|
48
|
+
if (!this.apiKey) {
|
|
49
|
+
throw new AvatarError({
|
|
50
|
+
code: AVATAR_ERROR_CODES.PROVIDER_NOT_CONFIGURED,
|
|
51
|
+
message: "DID_API_KEY not configured",
|
|
52
|
+
category: ErrorCategory.CONFIGURATION,
|
|
53
|
+
severity: ErrorSeverity.HIGH,
|
|
54
|
+
retriable: false,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (!options.audio && !options.text) {
|
|
58
|
+
throw new AvatarError({
|
|
59
|
+
code: AVATAR_ERROR_CODES.AUDIO_REQUIRED,
|
|
60
|
+
message: "D-ID requires either `audio` (Buffer/path) or `text` (with voice id) to drive the talk",
|
|
61
|
+
category: ErrorCategory.VALIDATION,
|
|
62
|
+
severity: ErrorSeverity.MEDIUM,
|
|
63
|
+
retriable: false,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const startTime = Date.now();
|
|
67
|
+
// 1. Upload image (D-ID needs a hosted URL).
|
|
68
|
+
const sourceUrl = await this.uploadImage(options.image);
|
|
69
|
+
// 2. Optional audio upload.
|
|
70
|
+
const audioUrl = options.audio
|
|
71
|
+
? await this.uploadAudio(options.audio)
|
|
72
|
+
: undefined;
|
|
73
|
+
// 3. Submit talk.
|
|
74
|
+
const talkId = await this.submitTalk(options, sourceUrl, audioUrl);
|
|
75
|
+
// 4. Poll for completion.
|
|
76
|
+
const completed = await this.pollUntilDone(talkId, options.timeout ?? TOTAL_TIMEOUT_MS, options.abortSignal);
|
|
77
|
+
if (!completed.result_url) {
|
|
78
|
+
throw new AvatarError({
|
|
79
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
80
|
+
message: `D-ID talk ${talkId} completed but no result_url returned`,
|
|
81
|
+
category: ErrorCategory.EXECUTION,
|
|
82
|
+
severity: ErrorSeverity.HIGH,
|
|
83
|
+
retriable: false,
|
|
84
|
+
context: { talkId, completed },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// 5. Guard the provider-returned URL before fetching (SSRF — same threat
|
|
88
|
+
// model as caller-supplied URLs: the API response could be tampered).
|
|
89
|
+
try {
|
|
90
|
+
await assertSafeUrl(completed.result_url);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
throw new AvatarError({
|
|
94
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
95
|
+
message: `D-ID result_url rejected as unsafe: ${err instanceof Error ? err.message : String(err)}`,
|
|
96
|
+
category: ErrorCategory.VALIDATION,
|
|
97
|
+
severity: ErrorSeverity.HIGH,
|
|
98
|
+
retriable: false,
|
|
99
|
+
context: { talkId, url: completed.result_url },
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
// 6. Download the MP4.
|
|
103
|
+
const buffer = await this.downloadResult(completed.result_url);
|
|
104
|
+
const latency = Date.now() - startTime;
|
|
105
|
+
logger.info(`[DIDAvatar] Generated ${buffer.length} bytes in ${latency}ms — talk ${talkId}`);
|
|
106
|
+
return {
|
|
107
|
+
buffer,
|
|
108
|
+
format: "mp4",
|
|
109
|
+
size: buffer.length,
|
|
110
|
+
duration: completed.duration,
|
|
111
|
+
provider: "d-id",
|
|
112
|
+
metadata: {
|
|
113
|
+
latency,
|
|
114
|
+
provider: "d-id",
|
|
115
|
+
jobId: talkId,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
async uploadImage(image) {
|
|
120
|
+
// If an HTTPS URL is provided directly, use it (D-ID accepts public URLs).
|
|
121
|
+
if (typeof image === "string" && /^https:\/\//.test(image)) {
|
|
122
|
+
return image;
|
|
123
|
+
}
|
|
124
|
+
const buffer = await this.resolveBuffer(image);
|
|
125
|
+
const form = new FormData();
|
|
126
|
+
form.append("image", new Blob([new Uint8Array(buffer)], {
|
|
127
|
+
type: this.detectImageMime(buffer),
|
|
128
|
+
}), "source.png");
|
|
129
|
+
const response = await this.fetchWithTimeout(`${this.baseUrl}/images`, {
|
|
130
|
+
method: "POST",
|
|
131
|
+
headers: {
|
|
132
|
+
Authorization: `Basic ${this.apiKey}`,
|
|
133
|
+
},
|
|
134
|
+
body: form,
|
|
135
|
+
});
|
|
136
|
+
const data = (await this.assertOk(response, "image upload"));
|
|
137
|
+
if (!data.url) {
|
|
138
|
+
throw new AvatarError({
|
|
139
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
140
|
+
message: "D-ID image upload succeeded but returned no URL",
|
|
141
|
+
category: ErrorCategory.EXECUTION,
|
|
142
|
+
severity: ErrorSeverity.HIGH,
|
|
143
|
+
retriable: false,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return data.url;
|
|
147
|
+
}
|
|
148
|
+
async uploadAudio(audio) {
|
|
149
|
+
if (typeof audio === "string" && /^https:\/\//.test(audio)) {
|
|
150
|
+
return audio;
|
|
151
|
+
}
|
|
152
|
+
const buffer = await this.resolveBuffer(audio);
|
|
153
|
+
const audioSubtype = this.detectAudioType(buffer);
|
|
154
|
+
// Map the detected subtype to a file extension.
|
|
155
|
+
const extMap = {
|
|
156
|
+
mp3: "mp3",
|
|
157
|
+
mpeg: "mp3",
|
|
158
|
+
wav: "wav",
|
|
159
|
+
ogg: "ogg",
|
|
160
|
+
mp4: "m4a",
|
|
161
|
+
};
|
|
162
|
+
const ext = extMap[audioSubtype] ?? "mp3";
|
|
163
|
+
const form = new FormData();
|
|
164
|
+
form.append("audio", new Blob([new Uint8Array(buffer)], { type: `audio/${audioSubtype}` }), `narration.${ext}`);
|
|
165
|
+
const response = await this.fetchWithTimeout(`${this.baseUrl}/audios`, {
|
|
166
|
+
method: "POST",
|
|
167
|
+
headers: {
|
|
168
|
+
Authorization: `Basic ${this.apiKey}`,
|
|
169
|
+
},
|
|
170
|
+
body: form,
|
|
171
|
+
});
|
|
172
|
+
const data = (await this.assertOk(response, "audio upload"));
|
|
173
|
+
if (!data.url) {
|
|
174
|
+
throw new AvatarError({
|
|
175
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
176
|
+
message: "D-ID audio upload succeeded but returned no URL",
|
|
177
|
+
category: ErrorCategory.EXECUTION,
|
|
178
|
+
severity: ErrorSeverity.HIGH,
|
|
179
|
+
retriable: false,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return data.url;
|
|
183
|
+
}
|
|
184
|
+
async submitTalk(options, sourceUrl, audioUrl) {
|
|
185
|
+
const script = audioUrl
|
|
186
|
+
? { type: "audio", audio_url: audioUrl }
|
|
187
|
+
: {
|
|
188
|
+
type: "text",
|
|
189
|
+
input: options.text,
|
|
190
|
+
provider: {
|
|
191
|
+
type: "microsoft",
|
|
192
|
+
voice_id: options.voice ?? "en-US-JennyNeural",
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
const body = {
|
|
196
|
+
source_url: sourceUrl,
|
|
197
|
+
script,
|
|
198
|
+
config: {
|
|
199
|
+
result_format: "mp4",
|
|
200
|
+
stitch: true,
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
const response = await this.fetchWithTimeout(`${this.baseUrl}/talks`, {
|
|
204
|
+
method: "POST",
|
|
205
|
+
headers: {
|
|
206
|
+
Authorization: `Basic ${this.apiKey}`,
|
|
207
|
+
"Content-Type": "application/json",
|
|
208
|
+
},
|
|
209
|
+
body: JSON.stringify(body),
|
|
210
|
+
});
|
|
211
|
+
const data = (await this.assertOk(response, "talk submit"));
|
|
212
|
+
if (!data.id) {
|
|
213
|
+
throw new AvatarError({
|
|
214
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
215
|
+
message: "D-ID talk submit returned no id",
|
|
216
|
+
category: ErrorCategory.EXECUTION,
|
|
217
|
+
severity: ErrorSeverity.HIGH,
|
|
218
|
+
retriable: false,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return data.id;
|
|
222
|
+
}
|
|
223
|
+
async pollUntilDone(talkId, totalTimeoutMs, abortSignal) {
|
|
224
|
+
const startTime = Date.now();
|
|
225
|
+
while (Date.now() - startTime < totalTimeoutMs) {
|
|
226
|
+
if (abortSignal?.aborted) {
|
|
227
|
+
throw new AvatarError({
|
|
228
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
229
|
+
message: `D-ID poll for talk ${talkId} aborted by caller`,
|
|
230
|
+
category: ErrorCategory.NETWORK,
|
|
231
|
+
severity: ErrorSeverity.MEDIUM,
|
|
232
|
+
retriable: false,
|
|
233
|
+
context: { talkId },
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const response = await this.fetchWithTimeout(`${this.baseUrl}/talks/${talkId}`, {
|
|
237
|
+
method: "GET",
|
|
238
|
+
headers: { Authorization: `Basic ${this.apiKey}` },
|
|
239
|
+
}, abortSignal);
|
|
240
|
+
const data = (await this.assertOk(response, "talk status"));
|
|
241
|
+
if (data.status === "done") {
|
|
242
|
+
return data;
|
|
243
|
+
}
|
|
244
|
+
if (data.status === "error" || data.status === "rejected") {
|
|
245
|
+
throw new AvatarError({
|
|
246
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
247
|
+
message: `D-ID talk ${talkId} ${data.status}: ${data.error?.description ?? "unknown"}`,
|
|
248
|
+
category: ErrorCategory.EXECUTION,
|
|
249
|
+
severity: ErrorSeverity.HIGH,
|
|
250
|
+
retriable: false,
|
|
251
|
+
context: { talkId, status: data.status, error: data.error },
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
// Abortable sleep.
|
|
255
|
+
await new Promise((resolve, reject) => {
|
|
256
|
+
const onAbort = () => {
|
|
257
|
+
clearTimeout(timer);
|
|
258
|
+
reject(new AvatarError({
|
|
259
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
260
|
+
message: `D-ID poll for talk ${talkId} aborted by caller`,
|
|
261
|
+
category: ErrorCategory.NETWORK,
|
|
262
|
+
severity: ErrorSeverity.MEDIUM,
|
|
263
|
+
retriable: false,
|
|
264
|
+
context: { talkId },
|
|
265
|
+
}));
|
|
266
|
+
};
|
|
267
|
+
const timer = setTimeout(() => {
|
|
268
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
269
|
+
resolve();
|
|
270
|
+
}, POLL_INTERVAL_MS);
|
|
271
|
+
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
throw new AvatarError({
|
|
275
|
+
code: AVATAR_ERROR_CODES.POLL_TIMEOUT,
|
|
276
|
+
message: `D-ID talk ${talkId} did not complete within ${Math.round(totalTimeoutMs / 1000)}s`,
|
|
277
|
+
category: ErrorCategory.TIMEOUT,
|
|
278
|
+
severity: ErrorSeverity.MEDIUM,
|
|
279
|
+
retriable: true,
|
|
280
|
+
context: { talkId },
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
async downloadResult(url) {
|
|
284
|
+
const response = await this.fetchWithTimeout(url, { method: "GET" });
|
|
285
|
+
if (!response.ok) {
|
|
286
|
+
throw new AvatarError({
|
|
287
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
288
|
+
message: `D-ID result download failed: ${response.status}`,
|
|
289
|
+
category: ErrorCategory.NETWORK,
|
|
290
|
+
severity: ErrorSeverity.MEDIUM,
|
|
291
|
+
retriable: response.status >= 500,
|
|
292
|
+
context: { status: response.status, url },
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
return await readBoundedBuffer(response, MAX_VIDEO_BYTES, "D-ID result");
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
throw new AvatarError({
|
|
300
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
301
|
+
message: `D-ID result download rejected: ${err instanceof Error ? err.message : String(err)}`,
|
|
302
|
+
category: ErrorCategory.NETWORK,
|
|
303
|
+
severity: ErrorSeverity.HIGH,
|
|
304
|
+
retriable: false,
|
|
305
|
+
context: { url },
|
|
306
|
+
originalError: err instanceof Error ? err : undefined,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async resolveBuffer(input) {
|
|
311
|
+
if (Buffer.isBuffer(input)) {
|
|
312
|
+
return input;
|
|
313
|
+
}
|
|
314
|
+
// Reject local file paths — only Buffer or HTTPS URLs are accepted.
|
|
315
|
+
if (!/^https:\/\//.test(input)) {
|
|
316
|
+
throw new AvatarError({
|
|
317
|
+
code: AVATAR_ERROR_CODES.INVALID_INPUT,
|
|
318
|
+
message: `Invalid input: expected Buffer or HTTPS URL, got string "${input}". Local file reads are not supported.`,
|
|
319
|
+
category: ErrorCategory.VALIDATION,
|
|
320
|
+
severity: ErrorSeverity.HIGH,
|
|
321
|
+
retriable: false,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
await assertSafeUrl(input);
|
|
326
|
+
}
|
|
327
|
+
catch (err) {
|
|
328
|
+
throw new AvatarError({
|
|
329
|
+
code: AVATAR_ERROR_CODES.INVALID_INPUT,
|
|
330
|
+
message: `Unsafe URL rejected: ${err instanceof Error ? err.message : String(err)}`,
|
|
331
|
+
category: ErrorCategory.VALIDATION,
|
|
332
|
+
severity: ErrorSeverity.HIGH,
|
|
333
|
+
retriable: false,
|
|
334
|
+
context: { url: input },
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
const response = await this.fetchWithTimeout(input, { method: "GET" });
|
|
338
|
+
if (!response.ok) {
|
|
339
|
+
throw new AvatarError({
|
|
340
|
+
code: AVATAR_ERROR_CODES.INVALID_INPUT,
|
|
341
|
+
message: `Failed to fetch input from ${input}: ${response.status}`,
|
|
342
|
+
category: ErrorCategory.NETWORK,
|
|
343
|
+
severity: ErrorSeverity.MEDIUM,
|
|
344
|
+
retriable: response.status >= 500,
|
|
345
|
+
context: { url: input, status: response.status },
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
// Use the larger of the two input caps (audio 50 MiB > image 25 MiB) so
|
|
349
|
+
// both audio and image URLs are bounded without falsely rejecting valid audio.
|
|
350
|
+
const inputCap = Math.max(MAX_AUDIO_BYTES, MAX_IMAGE_BYTES);
|
|
351
|
+
try {
|
|
352
|
+
return await readBoundedBuffer(response, inputCap, "D-ID input");
|
|
353
|
+
}
|
|
354
|
+
catch (err) {
|
|
355
|
+
throw new AvatarError({
|
|
356
|
+
code: AVATAR_ERROR_CODES.INVALID_INPUT,
|
|
357
|
+
message: `D-ID input download rejected: ${err instanceof Error ? err.message : String(err)}`,
|
|
358
|
+
category: ErrorCategory.NETWORK,
|
|
359
|
+
severity: ErrorSeverity.HIGH,
|
|
360
|
+
retriable: false,
|
|
361
|
+
context: { url: input },
|
|
362
|
+
originalError: err instanceof Error ? err : undefined,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
detectImageMime(buffer) {
|
|
367
|
+
if (buffer.length < 4) {
|
|
368
|
+
return "image/jpeg";
|
|
369
|
+
}
|
|
370
|
+
if (buffer[0] === 0x89 && buffer[1] === 0x50) {
|
|
371
|
+
return "image/png";
|
|
372
|
+
}
|
|
373
|
+
if (buffer[0] === 0xff && buffer[1] === 0xd8) {
|
|
374
|
+
return "image/jpeg";
|
|
375
|
+
}
|
|
376
|
+
// RIFF container: check offset 8 to distinguish WebP from WAV.
|
|
377
|
+
// A WAV file also begins with RIFF but carries "WAVE" at offset 8.
|
|
378
|
+
// If we can't confirm the WEBP four-CC we fall back to jpeg so callers
|
|
379
|
+
// that accidentally pass audio here get a visible mismatch rather than
|
|
380
|
+
// a silent wrong content-type.
|
|
381
|
+
if (buffer.length >= 12 &&
|
|
382
|
+
buffer[0] === 0x52 &&
|
|
383
|
+
buffer[1] === 0x49 &&
|
|
384
|
+
buffer[2] === 0x46 &&
|
|
385
|
+
buffer[3] === 0x46) {
|
|
386
|
+
if (buffer[8] === 0x57 &&
|
|
387
|
+
buffer[9] === 0x45 &&
|
|
388
|
+
buffer[10] === 0x42 &&
|
|
389
|
+
buffer[11] === 0x50) {
|
|
390
|
+
return "image/webp";
|
|
391
|
+
}
|
|
392
|
+
// RIFF but not WEBP (e.g. WAVE audio) — not a valid image.
|
|
393
|
+
return "image/jpeg";
|
|
394
|
+
}
|
|
395
|
+
return "image/jpeg";
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Detect the audio subtype from magic bytes.
|
|
399
|
+
*
|
|
400
|
+
* Recognised formats:
|
|
401
|
+
* - WAV : RIFF header (52 49 46 46)
|
|
402
|
+
* - OGG : OggS capture (4F 67 67 53)
|
|
403
|
+
* - MP3 : ID3 tag (49 44 33) or MPEG sync word (FF Ex)
|
|
404
|
+
* - M4A : "ftyp" box at offset 4 (ISO base media / M4A)
|
|
405
|
+
*
|
|
406
|
+
* Falls back to "mp3" when detection is inconclusive.
|
|
407
|
+
*/
|
|
408
|
+
detectAudioType(buffer) {
|
|
409
|
+
if (buffer.length < 4) {
|
|
410
|
+
return "mp3";
|
|
411
|
+
}
|
|
412
|
+
// WAV: RIFF header
|
|
413
|
+
if (buffer[0] === 0x52 &&
|
|
414
|
+
buffer[1] === 0x49 &&
|
|
415
|
+
buffer[2] === 0x46 &&
|
|
416
|
+
buffer[3] === 0x46) {
|
|
417
|
+
return "wav";
|
|
418
|
+
}
|
|
419
|
+
// OGG: OggS capture pattern
|
|
420
|
+
if (buffer[0] === 0x4f &&
|
|
421
|
+
buffer[1] === 0x67 &&
|
|
422
|
+
buffer[2] === 0x67 &&
|
|
423
|
+
buffer[3] === 0x53) {
|
|
424
|
+
return "ogg";
|
|
425
|
+
}
|
|
426
|
+
// MP3: ID3 header
|
|
427
|
+
if (buffer[0] === 0x49 && buffer[1] === 0x44 && buffer[2] === 0x33) {
|
|
428
|
+
return "mp3";
|
|
429
|
+
}
|
|
430
|
+
// MP3: MPEG sync word (0xFF 0xE0–0xFF)
|
|
431
|
+
if (buffer[0] === 0xff && (buffer[1] & 0xe0) === 0xe0) {
|
|
432
|
+
return "mpeg";
|
|
433
|
+
}
|
|
434
|
+
// M4A / AAC: "ftyp" box at offset 4
|
|
435
|
+
if (buffer.length >= 8 &&
|
|
436
|
+
buffer[4] === 0x66 &&
|
|
437
|
+
buffer[5] === 0x74 &&
|
|
438
|
+
buffer[6] === 0x79 &&
|
|
439
|
+
buffer[7] === 0x70) {
|
|
440
|
+
return "mp4";
|
|
441
|
+
}
|
|
442
|
+
return "mp3";
|
|
443
|
+
}
|
|
444
|
+
async fetchWithTimeout(url, init, callerAbortSignal) {
|
|
445
|
+
const controller = new AbortController();
|
|
446
|
+
const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
447
|
+
// Forward caller abort into this request so in-flight polls can be
|
|
448
|
+
// cancelled immediately without waiting for the timeout to fire.
|
|
449
|
+
const onCallerAbort = () => controller.abort();
|
|
450
|
+
callerAbortSignal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
451
|
+
try {
|
|
452
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
453
|
+
}
|
|
454
|
+
catch (err) {
|
|
455
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
456
|
+
// Distinguish an intentional caller cancellation from an internal
|
|
457
|
+
// timeout so the caller gets the right error semantics.
|
|
458
|
+
if (callerAbortSignal?.aborted) {
|
|
459
|
+
throw new AvatarError({
|
|
460
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
461
|
+
message: `D-ID request to ${url} aborted by caller`,
|
|
462
|
+
category: ErrorCategory.NETWORK,
|
|
463
|
+
severity: ErrorSeverity.MEDIUM,
|
|
464
|
+
retriable: false,
|
|
465
|
+
originalError: err,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
throw new AvatarError({
|
|
469
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
470
|
+
message: `D-ID request to ${url} timed out after ${REQUEST_TIMEOUT_MS / 1000}s`,
|
|
471
|
+
category: ErrorCategory.NETWORK,
|
|
472
|
+
severity: ErrorSeverity.HIGH,
|
|
473
|
+
retriable: true,
|
|
474
|
+
originalError: err,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
throw err;
|
|
478
|
+
}
|
|
479
|
+
finally {
|
|
480
|
+
callerAbortSignal?.removeEventListener("abort", onCallerAbort);
|
|
481
|
+
clearTimeout(timeoutId);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
async assertOk(response, label) {
|
|
485
|
+
if (response.ok) {
|
|
486
|
+
return response.json();
|
|
487
|
+
}
|
|
488
|
+
const raw = await response.text();
|
|
489
|
+
const retriable = response.status === 408 ||
|
|
490
|
+
response.status === 429 ||
|
|
491
|
+
response.status >= 500;
|
|
492
|
+
throw new AvatarError({
|
|
493
|
+
code: AVATAR_ERROR_CODES.GENERATION_FAILED,
|
|
494
|
+
message: `D-ID ${label} failed: ${response.status} — ${sanitizeForLog(raw, 500)}`,
|
|
495
|
+
category: retriable ? ErrorCategory.NETWORK : ErrorCategory.EXECUTION,
|
|
496
|
+
severity: ErrorSeverity.HIGH,
|
|
497
|
+
retriable,
|
|
498
|
+
context: { status: response.status, label },
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HeyGen Avatar Handler
|
|
3
|
+
*
|
|
4
|
+
* Async talking-head generation. Submits a video.generate request, polls
|
|
5
|
+
* the video status, downloads the result MP4.
|
|
6
|
+
*
|
|
7
|
+
* @module avatar/providers/HeyGenAvatar
|
|
8
|
+
* @see https://docs.heygen.com/reference/avatar-video
|
|
9
|
+
*/
|
|
10
|
+
import type { AvatarHandler, AvatarOptions, AvatarResult, AvatarVideoFormat } from "../../types/index.js";
|
|
11
|
+
/**
|
|
12
|
+
* HeyGen Avatar Handler.
|
|
13
|
+
*
|
|
14
|
+
* Auth: `X-API-Key: ${HEYGEN_API_KEY}`. The HeyGen API expects an
|
|
15
|
+
* `avatar_id` (HeyGen's own avatar catalog) — pass it via `options.voice`
|
|
16
|
+
* for legacy callers, or `options.avatarId` for explicit users.
|
|
17
|
+
*/
|
|
18
|
+
export declare class HeyGenAvatar implements AvatarHandler {
|
|
19
|
+
readonly maxAudioDurationSeconds = 300;
|
|
20
|
+
readonly supportedFormats: readonly AvatarVideoFormat[];
|
|
21
|
+
private readonly apiKey;
|
|
22
|
+
private readonly baseUrl;
|
|
23
|
+
constructor(apiKey?: string);
|
|
24
|
+
isConfigured(): boolean;
|
|
25
|
+
generate(options: AvatarOptions): Promise<AvatarResult>;
|
|
26
|
+
private submitVideo;
|
|
27
|
+
private pollUntilComplete;
|
|
28
|
+
private download;
|
|
29
|
+
private fetchWithTimeout;
|
|
30
|
+
}
|