vidspotai-shared 1.0.79 → 1.0.81

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.
Files changed (31) hide show
  1. package/lib/globals/aiModels/enums.d.ts +5 -0
  2. package/lib/globals/aiModels/enums.d.ts.map +1 -1
  3. package/lib/globals/aiModels/enums.js +12 -1
  4. package/lib/globals/aiModels/providers/alibaba.d.ts.map +1 -1
  5. package/lib/globals/aiModels/providers/alibaba.js +159 -39
  6. package/lib/services/aiGen/aiGenFactory.service.d.ts +4 -1
  7. package/lib/services/aiGen/aiGenFactory.service.d.ts.map +1 -1
  8. package/lib/services/aiGen/aiGenFactory.service.js +13 -1
  9. package/lib/services/aiGen/index.d.ts +1 -0
  10. package/lib/services/aiGen/index.d.ts.map +1 -1
  11. package/lib/services/aiGen/index.js +1 -0
  12. package/lib/services/aiGen/providers/alibaba/alibaba.d.ts +34 -7
  13. package/lib/services/aiGen/providers/alibaba/alibaba.d.ts.map +1 -1
  14. package/lib/services/aiGen/providers/alibaba/alibaba.js +193 -75
  15. package/lib/services/aiGen/providers/google/google.service.d.ts +1 -0
  16. package/lib/services/aiGen/providers/google/google.service.d.ts.map +1 -1
  17. package/lib/services/aiGen/providers/google/google.service.js +55 -7
  18. package/lib/services/aiGen/providers/openai/openai.service.d.ts.map +1 -1
  19. package/lib/services/aiGen/providers/openai/openai.service.js +22 -10
  20. package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts.map +1 -1
  21. package/lib/services/aiGen/providers/pixverse/pixverse.service.js +71 -40
  22. package/lib/services/aiGen/transientRetry.d.ts +35 -0
  23. package/lib/services/aiGen/transientRetry.d.ts.map +1 -0
  24. package/lib/services/aiGen/transientRetry.js +106 -0
  25. package/package.json +6 -6
  26. package/lib/services/aiGen/providers/azure/azure.service.d.ts +0 -14
  27. package/lib/services/aiGen/providers/azure/azure.service.d.ts.map +0 -1
  28. package/lib/services/aiGen/providers/azure/azure.service.js +0 -108
  29. package/lib/services/aiGen/providers/azure/index.d.ts +0 -2
  30. package/lib/services/aiGen/providers/azure/index.d.ts.map +0 -1
  31. package/lib/services/aiGen/providers/azure/index.js +0 -17
@@ -12,7 +12,70 @@ const types_1 = require("../../../../globals/types");
12
12
  const firebase_1 = require("../../../../libs/firebase");
13
13
  const helpers_2 = require("../../../../utils/helpers");
14
14
  const logger_1 = require("../../../../utils/logger");
15
+ const errors_1 = require("../../../../utils/errors");
16
+ const transientRetry_1 = require("../../transientRetry");
15
17
  const crypto_1 = __importDefault(require("crypto"));
18
+ // PixVerse soft-failure ErrCodes (HTTP 200 body). 0 = success.
19
+ // 500090 — insufficient balance on the openapi account (operator must top up)
20
+ // 401xx — auth (apiKey empty/invalid)
21
+ const PIXVERSE_ERR_INSUFFICIENT_BALANCE = 500090;
22
+ /**
23
+ * Classify a PixVerse HTTP failure (non-2xx). Returns:
24
+ * - TransientHttpError for retryable cases (5xx, 429, and 404 — PixVerse's
25
+ * CloudFlare edge has been observed serving "404 page not found" for
26
+ * transiently-misrouted requests that succeed on retry, 2026-06-06 prod log)
27
+ * - UserFacingError for 401/403 auth (deploy/config bug — fail fast, no Slack)
28
+ * - raw Error for true 4xx (validation, etc.) — surface to Slack as bug
29
+ */
30
+ function classifyPixVerseHttpError(status, body, op) {
31
+ if (status === 401 || status === 403) {
32
+ return new errors_1.UserFacingError(`PixVerse rejected the API key (HTTP ${status}). Ask an operator to verify PIXVERSE_API_KEY.`, errors_1.USER_FACING_ERROR_CODES.PROVIDER_AUTH_ERROR);
33
+ }
34
+ if (status >= 500 || status === 429 || status === 404) {
35
+ return new transientRetry_1.TransientHttpError(status, `PixVerse ${op} transient HTTP ${status}: ${body.slice(0, 200)}`);
36
+ }
37
+ return new Error(`PixVerse ${op} failed (${status}): ${body}`);
38
+ }
39
+ /**
40
+ * Classify a PixVerse 200-response with non-zero ErrCode. Insufficient-balance
41
+ * is an operator concern (account top-up), not a per-user bug — we surface it
42
+ * as UserFacingError(ACCOUNT_QUOTA_EXCEEDED) so it logs as warn (no Slack
43
+ * page-storm per job) AND the daily ops-channel digest still picks up that
44
+ * the account is empty. Other ErrCodes are real provider/protocol bugs.
45
+ */
46
+ function classifyPixVerseApiError(errCode, errMsg, op) {
47
+ if (errCode === PIXVERSE_ERR_INSUFFICIENT_BALANCE) {
48
+ return new errors_1.UserFacingError("Video provider is temporarily unavailable. Please try a different model or retry shortly.", errors_1.USER_FACING_ERROR_CODES.ACCOUNT_QUOTA_EXCEEDED);
49
+ }
50
+ return new Error(`PixVerse ${op} API error (code ${errCode}): ${errMsg || "Unknown error"}`);
51
+ }
52
+ /**
53
+ * One-shot PixVerse POST/GET helper with shared transient-retry behavior.
54
+ * Returns the parsed JSON body, or throws a classified error.
55
+ */
56
+ async function pixverseFetch(url, init, op) {
57
+ return (0, transientRetry_1.withTransientRetry)(`pixverse:${op}`, async () => {
58
+ const resp = await fetch(url, init);
59
+ if (!resp.ok) {
60
+ const errText = await resp.text();
61
+ throw classifyPixVerseHttpError(resp.status, errText, op);
62
+ }
63
+ const data = await resp.json();
64
+ if (data.ErrCode !== undefined && data.ErrCode !== 0) {
65
+ throw classifyPixVerseApiError(data.ErrCode, data.ErrMsg ?? "", op);
66
+ }
67
+ return data;
68
+ }, {
69
+ onRetry: ({ attempt, maxAttempts, backoffMs, err }) => {
70
+ logger_1.logger.warn(`PixVerse ${op} transient error — retrying`, {
71
+ attempt,
72
+ maxAttempts,
73
+ backoffMs,
74
+ message: err.message,
75
+ });
76
+ },
77
+ });
78
+ }
16
79
  class PixVerseService extends baseAiGenProvider_service_1.BaseAiGenProviderService {
17
80
  constructor() {
18
81
  super(...arguments);
@@ -43,7 +106,7 @@ class PixVerseService extends baseAiGenProvider_service_1.BaseAiGenProviderServi
43
106
  extendBody.negative_prompt = params.negativePrompt;
44
107
  if (params.seed !== undefined)
45
108
  extendBody.seed = params.seed;
46
- const resp = await fetch(`${this.baseUrl}/extend/generate`, {
109
+ const data = await pixverseFetch(`${this.baseUrl}/extend/generate`, {
47
110
  method: "POST",
48
111
  headers: {
49
112
  "Content-Type": "application/json",
@@ -51,15 +114,7 @@ class PixVerseService extends baseAiGenProvider_service_1.BaseAiGenProviderServi
51
114
  "Ai-trace-id": traceId,
52
115
  },
53
116
  body: JSON.stringify(extendBody),
54
- });
55
- if (!resp.ok) {
56
- const errText = await resp.text();
57
- throw new Error(`PixVerse extendVideo failed (${resp.status}): ${errText}`);
58
- }
59
- const data = await resp.json();
60
- if (data.ErrCode !== 0) {
61
- throw new Error(`PixVerse API error: ${data.ErrMsg || "Unknown error"}`);
62
- }
117
+ }, "extendVideo");
63
118
  const videoId = data?.Resp?.video_id;
64
119
  if (!videoId)
65
120
  throw new Error("PixVerse extend did not return video_id");
@@ -94,7 +149,7 @@ class PixVerseService extends baseAiGenProvider_service_1.BaseAiGenProviderServi
94
149
  effectBody.water_mark = !params.watermark;
95
150
  if (params.motionMode)
96
151
  effectBody.motion_mode = params.motionMode;
97
- const resp = await fetch(`${this.baseUrl}/template/generate`, {
152
+ const data = await pixverseFetch(`${this.baseUrl}/template/generate`, {
98
153
  method: "POST",
99
154
  headers: {
100
155
  "Content-Type": "application/json",
@@ -102,15 +157,7 @@ class PixVerseService extends baseAiGenProvider_service_1.BaseAiGenProviderServi
102
157
  "Ai-trace-id": traceId,
103
158
  },
104
159
  body: JSON.stringify(effectBody),
105
- });
106
- if (!resp.ok) {
107
- const errText = await resp.text();
108
- throw new Error(`PixVerse effect generation failed (${resp.status}): ${errText}`);
109
- }
110
- const data = await resp.json();
111
- if (data.ErrCode !== 0) {
112
- throw new Error(`PixVerse API error: ${data.ErrMsg || "Unknown error"}`);
113
- }
160
+ }, "effectGeneration");
114
161
  const videoId = data?.Resp?.video_id;
115
162
  if (!videoId)
116
163
  throw new Error("PixVerse effect did not return video_id");
@@ -165,7 +212,7 @@ class PixVerseService extends baseAiGenProvider_service_1.BaseAiGenProviderServi
165
212
  body.image_url = params.inputImageUrl;
166
213
  }
167
214
  const endpoint = isImageToVideo ? `${this.baseUrl}/image/generate` : `${this.baseUrl}/text/generate`;
168
- const resp = await fetch(endpoint, {
215
+ const data = await pixverseFetch(endpoint, {
169
216
  method: "POST",
170
217
  headers: {
171
218
  "Content-Type": "application/json",
@@ -173,15 +220,7 @@ class PixVerseService extends baseAiGenProvider_service_1.BaseAiGenProviderServi
173
220
  "Ai-trace-id": traceId,
174
221
  },
175
222
  body: JSON.stringify(body),
176
- });
177
- if (!resp.ok) {
178
- const errText = await resp.text();
179
- throw new Error(`PixVerse generateVideo failed (${resp.status}): ${errText}`);
180
- }
181
- const data = await resp.json();
182
- if (data.ErrCode !== 0) {
183
- throw new Error(`PixVerse API error: ${data.ErrMsg || "Unknown error"}`);
184
- }
223
+ }, "generateVideo");
185
224
  const videoId = data?.Resp?.video_id;
186
225
  if (!videoId) {
187
226
  throw new Error("PixVerse API did not return video_id");
@@ -196,21 +235,13 @@ class PixVerseService extends baseAiGenProvider_service_1.BaseAiGenProviderServi
196
235
  // =========================================================
197
236
  async checkVideoStatus({ task, outputFilename, outputFilePath = "videos", }) {
198
237
  const traceId = crypto_1.default.randomUUID();
199
- const resp = await fetch(`${this.baseUrl}/result/${task}`, {
238
+ const data = await pixverseFetch(`${this.baseUrl}/result/${task}`, {
200
239
  method: "GET",
201
240
  headers: {
202
241
  "API-KEY": process.env.PIXVERSE_API_KEY,
203
242
  "Ai-trace-id": traceId,
204
243
  },
205
- });
206
- if (!resp.ok) {
207
- const errText = await resp.text();
208
- throw new Error(`PixVerse checkVideoStatus failed (${resp.status}): ${errText}`);
209
- }
210
- const data = await resp.json();
211
- if (data.ErrCode !== 0) {
212
- throw new Error(`PixVerse API error: ${data.ErrMsg || "Unknown error"}`);
213
- }
244
+ }, "checkVideoStatus");
214
245
  const status = data?.Resp?.status;
215
246
  // ---- Status Mapping ----
216
247
  switch (status) {
@@ -0,0 +1,35 @@
1
+ /**
2
+ * True when an error from `fetch()` / SDK call is a transient network failure
3
+ * worth retrying. False for application-layer errors (4xx, validation, etc.).
4
+ */
5
+ export declare function isTransientFetchError(err: unknown): boolean;
6
+ /**
7
+ * Marker thrown by callers when they detect a transient HTTP response (5xx /
8
+ * 429 / opt-in 404) and want `withTransientRetry` to retry it. Caller is
9
+ * responsible for the classification — this util is response-shape agnostic.
10
+ */
11
+ export declare class TransientHttpError extends Error {
12
+ readonly isTransientHttpError = true;
13
+ readonly status: number;
14
+ constructor(status: number, message: string);
15
+ }
16
+ export interface TransientRetryOptions {
17
+ /** Max attempts including the first try. Defaults to 3. */
18
+ maxAttempts?: number;
19
+ /** Base backoff in ms; doubled each retry. Defaults to 1000 (1s → 2s → 4s). */
20
+ baseBackoffMs?: number;
21
+ /** Logger function for warn-level retry notices. */
22
+ onRetry?: (info: {
23
+ attempt: number;
24
+ maxAttempts: number;
25
+ backoffMs: number;
26
+ err: Error;
27
+ }) => void;
28
+ }
29
+ /**
30
+ * Wraps `fn` with retry on transient errors. UserFacingError ALWAYS short-
31
+ * circuits (no retry, no logging — caller's responsibility to log appropriately).
32
+ * Non-transient errors short-circuit on the first attempt.
33
+ */
34
+ export declare function withTransientRetry<T>(label: string, fn: () => Promise<T>, opts?: TransientRetryOptions): Promise<T>;
35
+ //# sourceMappingURL=transientRetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transientRetry.d.ts","sourceRoot":"","sources":["../../../src/services/aiGen/transientRetry.ts"],"names":[],"mappings":"AAwCA;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAQ3D;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,oBAAoB,QAAQ;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBACZ,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK5C;AAED,MAAM,WAAW,qBAAqB;IACpC,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,KAAK,CAAA;KAAE,KAAK,IAAI,CAAC;CACnG;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,CAAC,CAAC,CA2BZ"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ // Shared transient-error retry primitive for provider service calls.
3
+ //
4
+ // Background: every provider (Google, PixVerse, Alibaba, ...) makes outbound
5
+ // HTTP/SDK calls that can drop on transient network failures (TCP resets,
6
+ // undici fetch hiccups, upstream 5xx, CloudFlare edge 404 misroutes, etc.).
7
+ // Before this util each provider classified transient errors inline or not at
8
+ // all, so the same edge hiccup that retried OK on Google would fail-fast on
9
+ // PixVerse — fan-out inconsistency that bit us with the 2026-06-06 PixVerse
10
+ // 404 (the request body was valid, the account had a real account-level
11
+ // problem, but the response shape was an HTML "404 page not found" from the
12
+ // edge layer — a one-shot we'd have absorbed silently with a retry).
13
+ //
14
+ // Policy:
15
+ // - retry on undici "fetch failed" + the network-code allowlist below
16
+ // - retry on HTTP 5xx + 429 + 404 (404 ONLY when the URL is known-good and the
17
+ // caller opted in via `retryHttp4xx404`; otherwise 4xx is permanent)
18
+ // - never retry UserFacingError — those are deterministic by construction
19
+ // (content moderation, validation, missing input) and a retry just burns
20
+ // a provider credit for the same outcome
21
+ //
22
+ // Backoff: exponential 1s → 2s → 4s by default. Override via `backoffMs`.
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.TransientHttpError = void 0;
25
+ exports.isTransientFetchError = isTransientFetchError;
26
+ exports.withTransientRetry = withTransientRetry;
27
+ const errors_1 = require("../../utils/errors");
28
+ // Codes from undici / Node net layer that indicate a transient network failure
29
+ // (request never reached server, or server hung up mid-flight). Retrying these
30
+ // is safe at the API layer for our use cases.
31
+ const TRANSIENT_NETWORK_CODES = new Set([
32
+ "ECONNRESET",
33
+ "ECONNREFUSED",
34
+ "ETIMEDOUT",
35
+ "ENOTFOUND",
36
+ "EAI_AGAIN",
37
+ "EPIPE",
38
+ "UND_ERR_SOCKET",
39
+ "UND_ERR_CONNECT_TIMEOUT",
40
+ "UND_ERR_HEADERS_TIMEOUT",
41
+ "UND_ERR_BODY_TIMEOUT",
42
+ ]);
43
+ /**
44
+ * True when an error from `fetch()` / SDK call is a transient network failure
45
+ * worth retrying. False for application-layer errors (4xx, validation, etc.).
46
+ */
47
+ function isTransientFetchError(err) {
48
+ if (!err)
49
+ return false;
50
+ const e = err;
51
+ // undici wraps low-level errors as `TypeError: fetch failed` with the real
52
+ // reason on `err.cause`. Treat that exact shape as transient.
53
+ if (e.message === "fetch failed")
54
+ return true;
55
+ const code = e.code ?? e.cause?.code;
56
+ return !!code && TRANSIENT_NETWORK_CODES.has(code);
57
+ }
58
+ /**
59
+ * Marker thrown by callers when they detect a transient HTTP response (5xx /
60
+ * 429 / opt-in 404) and want `withTransientRetry` to retry it. Caller is
61
+ * responsible for the classification — this util is response-shape agnostic.
62
+ */
63
+ class TransientHttpError extends Error {
64
+ constructor(status, message) {
65
+ super(message);
66
+ this.isTransientHttpError = true;
67
+ this.name = "TransientHttpError";
68
+ this.status = status;
69
+ }
70
+ }
71
+ exports.TransientHttpError = TransientHttpError;
72
+ /**
73
+ * Wraps `fn` with retry on transient errors. UserFacingError ALWAYS short-
74
+ * circuits (no retry, no logging — caller's responsibility to log appropriately).
75
+ * Non-transient errors short-circuit on the first attempt.
76
+ */
77
+ async function withTransientRetry(label, fn, opts = {}) {
78
+ const maxAttempts = opts.maxAttempts ?? 3;
79
+ const baseBackoffMs = opts.baseBackoffMs ?? 1000;
80
+ let lastErr;
81
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
82
+ try {
83
+ return await fn();
84
+ }
85
+ catch (err) {
86
+ lastErr = err;
87
+ // UserFacingError is by-construction deterministic — never retry.
88
+ if (err instanceof errors_1.UserFacingError)
89
+ throw err;
90
+ const transient = isTransientFetchError(err) ||
91
+ (err instanceof TransientHttpError);
92
+ if (!transient || attempt === maxAttempts)
93
+ throw err;
94
+ const backoffMs = baseBackoffMs * 2 ** (attempt - 1);
95
+ opts.onRetry?.({
96
+ attempt,
97
+ maxAttempts,
98
+ backoffMs,
99
+ err: err,
100
+ });
101
+ void label; // label is for tracing in caller's onRetry; intentionally unused here
102
+ await new Promise((r) => setTimeout(r, backoffMs));
103
+ }
104
+ }
105
+ throw lastErr;
106
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vidspotai-shared",
3
- "version": "1.0.79",
3
+ "version": "1.0.81",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "exports": {
@@ -13,6 +13,10 @@
13
13
  "files": [
14
14
  "lib"
15
15
  ],
16
+ "scripts": {
17
+ "build": "tsc -p tsconfig.json",
18
+ "watch": "tsc -p tsconfig.json --watch"
19
+ },
16
20
  "dependencies": {
17
21
  "@anthropic-ai/sdk": "^0.98.0",
18
22
  "@google-cloud/storage": "*",
@@ -43,9 +47,5 @@
43
47
  "peerDependencies": {
44
48
  "firebase-admin": "^13.5.0",
45
49
  "ioredis": "^5.8.0"
46
- },
47
- "scripts": {
48
- "build": "tsc -p tsconfig.json",
49
- "watch": "tsc -p tsconfig.json --watch"
50
50
  }
51
- }
51
+ }
@@ -1,14 +0,0 @@
1
- import { BaseAiGenProviderService } from "../baseAiGenProvider.service";
2
- import { CreditUsageParams, VideoGenerationParams, VideoGenerationResult, VideoStatusParams, VideoStatusResult } from "../types";
3
- export declare class AzureService extends BaseAiGenProviderService {
4
- private readonly baseUrl;
5
- private readonly apiKey;
6
- private readonly apiVersion;
7
- private readonly timeout;
8
- constructor();
9
- private request;
10
- generateVideo(params: VideoGenerationParams): Promise<VideoGenerationResult>;
11
- checkVideoStatus({ task, outputFilename, outputFilePath, }: VideoStatusParams): Promise<VideoStatusResult>;
12
- getCreditUsed({ modelKey, dimensions, duration, multiClip, }: CreditUsageParams): number;
13
- }
14
- //# sourceMappingURL=azure.service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"azure.service.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/azure/azure.service.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAElB,qBAAa,YAAa,SAAQ,wBAAwB;IACxD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;;YAiBnB,OAAO;IAwBf,aAAa,CACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IA6B3B,gBAAgB,CAAC,EACrB,IAAI,EACJ,cAAc,EACd,cAAyB,GAC1B,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAgDjD,aAAa,CAAC,EACZ,QAAQ,EACR,UAAsB,EACtB,QAAY,EACZ,SAAiB,GAClB,EAAE,iBAAiB,GAAG,MAAM;CAS9B"}
@@ -1,108 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.AzureService = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
- const aiModels_1 = require("../../../../globals/aiModels");
9
- const types_1 = require("../../../../globals/types");
10
- const firebase_1 = require("../../../../libs/firebase");
11
- const helpers_1 = require("../../../../utils/helpers");
12
- const logger_1 = require("../../../../utils/logger");
13
- const helpers_2 = require("../../helpers");
14
- const baseAiGenProvider_service_1 = require("../baseAiGenProvider.service");
15
- class AzureService extends baseAiGenProvider_service_1.BaseAiGenProviderService {
16
- constructor() {
17
- super();
18
- this.apiVersion = "preview";
19
- this.timeout = 60000; // 60 seconds
20
- if (!process.env.AZURE_OPENAI_ENDPOINT ||
21
- !process.env.AZURE_OPENAI_API_KEY) {
22
- throw new Error("Missing AZURE_OPENAI_ENDPOINT or AZURE_OPENAI_API_KEY in environment variables");
23
- }
24
- this.baseUrl = process.env.AZURE_OPENAI_ENDPOINT;
25
- this.apiKey = process.env.AZURE_OPENAI_API_KEY;
26
- }
27
- async request(endpoint, method, body) {
28
- const url = `${this.baseUrl}${endpoint}${endpoint.includes("?") ? "&" : "?"}api-version=${this.apiVersion}`;
29
- const config = {
30
- method,
31
- url,
32
- headers: {
33
- "api-key": this.apiKey,
34
- "Content-Type": "application/json",
35
- },
36
- timeout: this.timeout,
37
- data: body,
38
- };
39
- const res = await axios_1.default.request(config);
40
- return res.data;
41
- }
42
- async generateVideo(params) {
43
- (0, helpers_2.validateParams)(params);
44
- const modelId = aiModels_1.aiModelConfigs[params.modelKey]?.modelId || "sora";
45
- const body = {
46
- prompt: params.prompt,
47
- width: params.dimensions?.split("x")[0]
48
- ? parseInt(params.dimensions.split("x")[0] ?? "480", 10)
49
- : 480,
50
- height: params.dimensions?.split("x")[1]
51
- ? parseInt(params.dimensions.split("x")[1] ?? "480", 10)
52
- : 480,
53
- n_seconds: params.duration || 5,
54
- model: modelId,
55
- };
56
- const job = await this.request(`/openai/v1/video/generations/jobs?`, "POST", body);
57
- return {
58
- task: job.id,
59
- status: types_1.EVideoSceneStatus.TRIGGERED,
60
- };
61
- }
62
- async checkVideoStatus({ task, outputFilename, outputFilePath = "videos", }) {
63
- const result = await this.request(`/openai/v1/video/generations/jobs/${task}?`, "GET");
64
- if (result.status === "succeeded") {
65
- if (!result.generations || !(result.generations.length > 0)) {
66
- return {
67
- status: types_1.EVideoSceneStatus.FAILED,
68
- errorMessage: "No video returned from API",
69
- };
70
- }
71
- const generationId = result.generations[0].id;
72
- const videoUrl = `${this.baseUrl}/openai/v1/video/generations/${generationId}/content/video?api-version=${this.apiVersion}`;
73
- const videoResp = await axios_1.default.get(videoUrl, {
74
- headers: { "api-key": this.apiKey },
75
- responseType: "arraybuffer",
76
- timeout: this.timeout,
77
- });
78
- if (!videoResp.data)
79
- throw new Error("No video data received from Azure API");
80
- const filePath = `${outputFilePath}/${outputFilename}.mp4`;
81
- const file = (0, firebase_1.getBucket)().file(filePath);
82
- const buffer = Buffer.from(videoResp.data);
83
- await file.save(buffer, { contentType: "video/mp4" });
84
- const [signedUrl] = await file.getSignedUrl({
85
- action: "read",
86
- expires: "03-09-2491",
87
- });
88
- return { videoUrl: signedUrl, status: types_1.EVideoSceneStatus.COMPLETED };
89
- }
90
- else if (result.status === "failed") {
91
- return {
92
- status: types_1.EVideoSceneStatus.FAILED,
93
- errorMessage: `Task failed: ${result.failure_reason || "unknown"}`,
94
- };
95
- }
96
- return { status: types_1.EVideoSceneStatus.PENDING };
97
- }
98
- getCreditUsed({ modelKey, dimensions = "480x480", duration = 5, multiClip = false, }) {
99
- const modelConfig = aiModels_1.aiModelConfigs[modelKey];
100
- const cost = modelConfig.cost?.table?.[dimensions]?.[duration];
101
- if (cost === undefined || cost === null) {
102
- logger_1.logger.warn(`Azure getCreditUsed: no cost entry for modelKey="${modelKey}" dimensions="${dimensions}" duration=${duration} — returning fallback`, { modelKey, dimensions, duration });
103
- return (0, helpers_1.getCreditsFromCost)(1.0, !multiClip);
104
- }
105
- return (0, helpers_1.getCreditsFromCost)(cost, !multiClip);
106
- }
107
- }
108
- exports.AzureService = AzureService;
@@ -1,2 +0,0 @@
1
- export * from "./azure.service";
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/services/aiGen/providers/azure/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
@@ -1,17 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./azure.service"), exports);