UNPKG

socaity

Version:

SDK for Generative AI. Build AI-powered applications with ease

1,565 lines (1,564 loc) 77.9 kB
var tt = Object.defineProperty; var et = (n, t, e) => t in n ? tt(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e; var a = (n, t, e) => et(n, typeof t != "symbol" ? t + "" : t, e); class D extends Error { constructor(t = "Invalid API key format. API keys should start with 'sk_' and be 67 characters long.") { super(t), this.name = "ApiKeyError", Error.captureStackTrace && Error.captureStackTrace(this, D); } } const P = class P { constructor(t = {}) { a(this, "apiKey"); a(this, "baseUrl"); a(this, "pollInterval"); a(this, "maxRetries"); this.apiKey = t.apiKey, this.baseUrl = "https://api.socaity.ai/v1", this.pollInterval = t.pollInterval || 5e3, this.maxRetries = t.maxRetries || 3; } /** * Get the global configuration instance */ static getInstance() { return P.instance || (P.instance = new P()), P.instance; } /** * Updates global configuration with new values */ static update(t) { if (t.apiKey !== void 0) { if (!t.apiKey.startsWith("sk_") && !t.apiKey.startsWith("tk_") && !t.apiKey.startsWith("ey")) throw new D("Invalid authentication token. Use either a Socaity API key from https://www.socaity.ai or a valid JWT token."); if (t.apiKey.startsWith("sk_") && !t.apiKey.startsWith("tk_") && t.apiKey.length !== 67) throw new D("Invalid API key format. API keys should be 67 characters long. Get your API key from https://www.socaity.ai"); } const e = P.getInstance(); Object.assign(e, t); } }; a(P, "instance"); let T = P; var u = /* @__PURE__ */ ((n) => (n.CREATED = "CREATED", n.QUEUED = "QUEUED", n.PROCESSING = "PROCESSING", n.COMPLETED = "COMPLETED", n.FAILED = "FAILED", n.UNKNOWN = "UNKNOWN", n))(u || {}), f = /* @__PURE__ */ ((n) => (n.INITIALIZING = "INITIALIZING", n.PREPARING = "PREPARING", n.SENDING = "SENDING", n.TRACKING = "TRACKING", n.PROCESSING_RESULT = "PROCESSING_RESULT", n.COMPLETED = "COMPLETED", n.FAILED = "FAILED", n))(f || {}); class rt { /** * Parse response into standardized job format * @param response - API response object or string * @returns Standardized SocaityJob object */ async parse(t) { if (t == null) return this.createErrorJob("No response received"); if (typeof t == "string") try { const e = JSON.parse(t); return this.parseObject(e); } catch { return { id: "", status: u.COMPLETED, progress: { progress: 1, message: null }, result: t, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() }; } return this.parseObject(t); } /** * Parse object responses into SocaityJob * @param response - Object to parse */ async parseObject(t) { if (typeof t != "object" || t === null) return this.createErrorJob("Invalid response format"); const e = t, r = typeof e.id == "string" ? e.id : "", s = this.parseStatus(e.status), i = this.parseProgress(e, s), o = typeof e.error == "string" ? e.error : null, l = typeof e.refresh_job_url == "string" ? e.refresh_job_url : void 0, h = this.parseDate(e.createdAt), c = this.parseDate(e.updatedAt); return { id: r, status: s, progress: i, result: e.result, error: o, createdAt: h, updatedAt: c, refresh_job_url: l }; } /** * Creates a standard error job response * @param errorMessage - Error message to include */ createErrorJob(t) { const e = /* @__PURE__ */ new Date(); return { id: "", status: u.FAILED, progress: { progress: 0, message: t }, result: null, error: t, createdAt: e, updatedAt: e }; } /** * Parse date from various formats * @param dateValue - Date value to parse */ parseDate(t) { if (t instanceof Date) return t; if (typeof t == "string" || typeof t == "number") { const e = new Date(t); if (!isNaN(e.getTime())) return e; } return /* @__PURE__ */ new Date(); } /** * Parse status from different API formats * @param status - Status string to parse */ parseStatus(t) { if (typeof t != "string" || !t) return u.UNKNOWN; const e = t.toUpperCase(); return { COMPLETED: u.COMPLETED, SUCCEEDED: u.COMPLETED, FINISHED: u.COMPLETED, CREATED: u.CREATED, FAILED: u.FAILED, ERROR: u.FAILED, IN_PROGRESS: u.PROCESSING, PROCESSING: u.PROCESSING, RUNNING: u.PROCESSING, BOOTING: u.PROCESSING, QUEUED: u.QUEUED, PENDING: u.QUEUED, IN_QUEUE: u.QUEUED, STARTING: u.QUEUED }[e] || u.UNKNOWN; } /** * Parse progress from different API formats * @param response - Response object containing progress information * @param status - Parsed job status */ parseProgress(t, e) { let r = 0, s = null; const i = t.progress; if (typeof i == "number") r = i; else if (typeof i == "string") try { r = parseFloat(i); } catch { r = 0; } else if (i && typeof i == "object") { const o = i; if (typeof o.progress == "number") r = o.progress; else if (typeof o.progress == "string") try { r = parseFloat(o.progress); } catch { r = 0; } s = typeof o.message == "string" ? o.message : null; } return isNaN(r) && (r = 0), r = Math.max(0, Math.min(1, r)), e === u.COMPLETED && (r = 1), !s && typeof t.message == "string" && (s = t.message), { progress: r, message: s }; } } var st = Object.defineProperty, it = (n, t, e) => t in n ? st(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e, k = (n, t, e) => it(n, typeof t != "symbol" ? t + "" : t, e); function z(n) { return n && typeof n == "object" && "file_name" in n && "content_type" in n && "content" in n; } const b = { mp3: "audio/mpeg", wav: "audio/wav", ogg: "audio/ogg", aac: "audio/aac", flac: "audio/flac", m4a: "audio/mp4", webm: "audio/webm" }, w = { mp4: "video/mp4", mov: "video/quicktime", avi: "video/x-msvideo", mkv: "video/x-matroska", wmv: "video/x-ms-wmv", webm: "video/webm", "3gp": "video/3gpp", flv: "video/x-flv" }, E = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp", svg: "image/svg+xml", bmp: "image/bmp", ico: "image/x-icon", tiff: "image/tiff", tif: "image/tiff", avif: "image/avif" }, nt = { pdf: "application/pdf", txt: "text/plain", html: "text/html", htm: "text/html", json: "application/json", js: "application/javascript", css: "text/css", xml: "application/xml", zip: "application/zip", csv: "text/csv", npz: "application/octet-stream" }, K = { ...b, ...w, ...E, ...nt }; function dt(n) { const t = []; switch (n) { case "audio": t.push(...Object.values(b)), t.push(...Object.keys(b).map((e) => `.${e}`)); break; case "video": t.push(...Object.values(w)), t.push(...Object.keys(w).map((e) => `.${e}`)); break; case "image": t.push(...Object.values(E)), t.push(...Object.keys(E).map((e) => `.${e}`)); break; case "file": default: return ["*/*"]; } return t; } function mt(n) { return { audio: "Audio", video: "Video", image: "Images", file: "Files" }[n] || n; } function gt(n) { return Object.values(b).includes(n) ? "audio" : Object.values(w).includes(n) ? "video" : Object.values(E).includes(n) ? "image" : null; } function H(n) { const t = (n.startsWith(".") ? n.slice(1) : n).toLowerCase(); return t in K ? K[t] : null; } const _ = typeof window > "u"; function B(n) { try { const t = new URL(n); return t.protocol === "http:" || t.protocol === "https:"; } catch { return !1; } } function yt(n) { if (typeof n != "string" || !B(n)) return null; try { const t = ((new URL(n).pathname || "").split("/").pop() || "").split("?")[0].split("#")[0].split("."), e = t.length > 1 ? t.pop().toLowerCase() : ""; return e ? H(e) : null; } catch { return null; } } function ot(n) { return n.startsWith("data:") || at(n); } function at(n) { return /^[A-Za-z0-9+/=]+$/.test(n) && n.length % 4 === 0; } async function lt(n) { if (!_) return !1; try { return (await (await import("fs/promises")).stat(n)).isFile(); } catch { return !1; } } function V(n) { return n && typeof n == "object" && typeof n.data == "string" && typeof n.type == "string" && typeof n.name == "string"; } async function Q(n) { if (n == null) return null; if (Array.isArray(n)) { const t = n.map((e) => Q(e)); return Promise.all(t); } if (z(n)) try { return await new p().fromDict(n); } catch { return n; } return n; } class L { /** * Create a MediaFile or specialized subclass from any supported data type. * Automatically detects data type and instantiates the appropriate class. * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to a MediaFile instance or specialized subclass */ static async create(t) { if (t == null) throw new Error("Cannot create MediaFile from null or undefined data"); const e = await L._detectContentType(t); let r = I.default; return e && e.startsWith("image/") ? r = I.image : e && e.startsWith("audio/") ? r = I.audio : e && e.startsWith("video/") && (r = I.video), new r().fromAny(t); } /** * Detects content type from various data sources. * * @param data - Data to detect content type from * @returns Promise resolving to the detected content type or null * @private */ static async _detectContentType(t) { var e; if (t instanceof p) return t.getContentType(); if (z(t)) return t.content_type; if (V(t)) return t.type; if (typeof t == "string" && B(t)) { const r = (e = new URL(t).pathname.split(".").pop()) == null ? void 0 : e.toLowerCase(); if (r) { const s = L._getMimeTypeFromExtension(r); if (s) return s; } try { const s = await fetch(t, { method: "HEAD", headers: { "User-Agent": "MediaFile/1.0.0" } }); if (s.ok) { const i = s.headers.get("content-type"); if (i) return i; } } catch { } } if (typeof t == "string" && t.startsWith("data:")) { const r = t.match(/^data:([^;,]+)/); if (r && r[1]) return r[1]; } if (typeof t == "string" && typeof window > "u") try { const r = await import("fs/promises"), s = await import("path"); await r.access(t); const i = s.extname(t).slice(1).toLowerCase(); if (i) { const o = L._getMimeTypeFromExtension(i); if (o) return o; } } catch { } return typeof Blob < "u" && t instanceof Blob ? t.type : null; } /** * Maps file extensions to MIME types. * * @param extension - File extension without the dot * @returns The corresponding MIME type or null * @private */ static _getMimeTypeFromExtension(t) { return H(t); } } class p { /** * Creates a new MediaFile instance. * * @param file_name - Default filename to use * @param content_type - Default content type to use */ constructor(t = "file", e = "application/octet-stream") { k(this, "content_type"), k(this, "file_name"), k(this, "_content", null), this.content_type = e, this.file_name = t; } /** * Factory method to create a MediaFile from any supported data type. * This is kept for backward compatibility. New code should use MediaFileFactory.create(). * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to a MediaFile instance or specialized subclass * @deprecated Use MediaFileFactory.create() instead */ static async create(t) { return L.create(t); } /** * Load a file from any supported data type. * * @param data - Data to load (file path, URL, base64 string, etc.) * @param websafe - Prevents loading from file paths and malformatted base64 strings. * @returns Promise resolving to a MediaFile instance or null */ async fromAny(t) { if (t == null) throw new Error("Cannot create MediaFile from null or undefined data"); if (t instanceof p) return t; if (V(t)) { if (this.file_name = t.name || "file", this.content_type = t.type, typeof t.data == "string") return this.fromBase64(t.data); throw new Error("Invalid data format in FileReader object"); } if (_ && this._isBuffer(t)) return this.fromBytes(t); if (typeof File < "u" && t instanceof File) { this.file_name = t.name, this.content_type = t.type || "application/octet-stream"; const e = await t.arrayBuffer(); return this.fromBytes(e); } if (typeof Blob < "u" && t instanceof Blob) { const e = await t.arrayBuffer(); return this.fromBytes(e); } if (t instanceof ArrayBuffer || t instanceof Uint8Array) return this.fromBytes(t); if (typeof t == "string") { if (B(t)) return await this.fromUrl(t); if (ot(t)) return this.fromBase64(t); if (await lt(t)) return await this.fromFile(t); throw typeof t == "string" ? new Error("Invalid data type for MediaFile " + t) : new Error("Invalid data type for MediaFile"); } return z(t) ? await this.fromDict(t) : this; } /** * Load file from a file path (Node.js only). * * @param filePath - Path to the file * @returns Promise resolving to the MediaFile instance */ async fromFile(t) { if (!_) throw new Error("Loading from file path is only supported in Node.js environment"); try { const e = await (await import("fs/promises")).readFile(t), r = await import("path"); return this.file_name = r.basename(t), this._content = this._bufferToArrayBuffer(e), this._setContentTypeFromFileName(), this; } catch (e) { throw new Error(`Failed to load file from path: ${t}. ${e.message}`); } } /** * Load file from a URL. * * @param url - URL to fetch the file from * @param headers - Optional headers for the request * @returns Promise resolving to the MediaFile instance */ async fromUrl(t, e) { const r = async (s, i) => await fetch(s, { headers: i || { "User-Agent": "MediaFile/1.0.0" } }); try { let s = await r(t, e); if (!s.ok) { if (s.status === 401 || s.status === 403) { const o = new URL(t); o.search = "", s = await r(o.toString(), e); } if (!s.ok) throw new Error(`HTTP error! Status: ${s.status}`); } this.content_type = s.headers.get("content-type") || "application/octet-stream"; const i = s.headers.get("content-disposition"); if (i) { const o = i.match(/filename=(?:['"]?)([^'";\n]+)/i); o && o[1] && (this.file_name = o[1]); } if (!this.file_name || this.file_name === "file") { const o = new URL(t).pathname.split("/"), l = o[o.length - 1]; l && l.trim() !== "" ? this.file_name = decodeURIComponent(l) : this.file_name = "downloaded_file"; } return this._content = await s.arrayBuffer(), this; } catch (s) { throw new Error(`Failed to load file from URL: ${t}. ${s.message}`); } } /** * Load file from base64 encoded string. * * @param base64Data - Base64 encoded string, optionally with data URI prefix * @returns The MediaFile instance */ fromBase64(t) { const { data: e, mediaType: r } = this._parseBase64Uri(t); r && (this.content_type = r); try { return this._content = _ ? this._decodeBase64NodeJs(e) : this._decodeBase64Browser(e), this; } catch (s) { throw new Error(`Failed to decode base64 data: ${s.message}`); } } /** * Load file from binary data. * * @param data - ArrayBuffer, Buffer, or Uint8Array containing the file data * @returns The MediaFile instance */ fromBytes(t) { if (typeof SharedArrayBuffer < "u" && t instanceof SharedArrayBuffer) { const e = new Uint8Array(t), r = new ArrayBuffer(e.byteLength); return new Uint8Array(r).set(e), this._content = r, this; } if (t instanceof Uint8Array) if (typeof SharedArrayBuffer < "u" && t.buffer instanceof SharedArrayBuffer) { const e = new Uint8Array(t); this._content = e.buffer.slice(e.byteOffset, e.byteOffset + e.byteLength); } else this._content = t.buffer.slice(t.byteOffset, t.byteOffset + t.byteLength); else if (_ && Buffer.isBuffer(t)) if (typeof SharedArrayBuffer < "u" && t.buffer instanceof SharedArrayBuffer) { const e = new Uint8Array(t); this._content = e.buffer.slice(e.byteOffset, e.byteOffset + e.byteLength); } else this._content = t.buffer.slice(t.byteOffset, t.byteOffset + t.byteLength); else this._content = new Uint8Array(t).buffer; return this; } /** * Load file from a FileResult object. * * @param fileResult - FileResult object with file metadata and base64 content * @returns The MediaFile instance */ async fromDict(t) { if (!t.content) throw new Error("Invalid FileResult object: missing content"); return this.file_name = t.file_name, this.content_type = t.content_type, await this.fromAny(t.content); } /** * Convert the file to a Blob (browser only). * * @returns Blob object representing the file */ toBlob() { if (this._ensureContent(), typeof Blob > "u") throw new Error("Blob is not available in this environment"); return new Blob([new Uint8Array(this._content)], { type: this.content_type }); } /** * Convert the file to an ArrayBuffer. * * @returns ArrayBuffer containing the file data */ toArrayBuffer() { return this._ensureContent(), typeof SharedArrayBuffer < "u" && this._content instanceof SharedArrayBuffer ? this._content.slice(0) : this._content; } /** * Convert the file to a Uint8Array. * * @returns Uint8Array containing the file data */ toUint8Array() { return this._ensureContent(), new Uint8Array(this._content); } /** * Convert the file to a Node.js Buffer (Node.js only). * * @returns Buffer containing the file data */ toBuffer() { if (this._ensureContent(), !_) throw new Error("Buffer is only available in Node.js environment"); return Buffer.from(this._content); } /** * Convert the file to a base64 encoded string. * * @param includeDataUri - Whether to include the data URI prefix * @returns Base64 encoded string of the file data */ toBase64(t = !0) { this._ensureContent(); let e; if (_) e = Buffer.from(this._content).toString("base64"); else { const r = new Uint8Array(this._content); let s = ""; const i = 10240; for (let o = 0; o < r.length; o += i) { const l = r.subarray(o, Math.min(o + i, r.length)); s += String.fromCharCode.apply(null, Array.from(l)); } e = btoa(s); } return t ? `data:${this.content_type};base64,${e}` : e; } /** * Convert the file to a FileResult object. * * @returns FileResult object with file metadata and base64 content */ toJson() { return { file_name: this.file_name, content_type: this.content_type, content: this.toBase64() }; } /** * Save the file to disk (Node.js) or trigger download (browser). * * @param filePath - Optional file path (Node.js) or filename (browser) * @returns Promise that resolves when the file is saved */ async save(t) { this._ensureContent(); const e = t || this.file_name; if (_) try { const r = await import("fs/promises").then((o) => o.default || o), s = await import("path").then((o) => o.default || o); if (!s || typeof s.dirname != "function") throw new Error("Failed to load 'path' module."); const i = s.dirname(e); i !== "." && await r.mkdir(i, { recursive: !0 }).catch(() => { }), await r.writeFile(e, Buffer.from(this._content)); } catch (r) { throw new Error(`Failed to save file: ${r.message}`); } else { const r = this.toBlob(), s = URL.createObjectURL(r), i = document.createElement("a"); i.href = s, i.download = e, document.body.appendChild(i), i.click(), setTimeout(() => { document.body.removeChild(i), URL.revokeObjectURL(s); }, 100); } } /** * Get the file size in bytes. * * @param unit - Unit to return the size in ('bytes', 'kb', 'mb', or 'gb') * @returns File size in the specified unit */ fileSize(t = "bytes") { if (!this._content) return 0; const e = this._content.byteLength; switch (t) { case "kb": return e / 1024; case "mb": return e / (1024 * 1024); case "gb": return e / (1024 * 1024 * 1024); default: return e; } } /** * Get the file extension based on the content type or filename. * * @returns File extension without the leading dot, or null if it cannot be determined */ get extension() { var t; if (this.content_type && this.content_type !== "application/octet-stream") { const e = { "image/jpeg": "jpg", "image/png": "png", "image/gif": "gif", "image/webp": "webp", "image/svg+xml": "svg", "audio/mpeg": "mp3", "audio/wav": "wav", "audio/ogg": "ogg", "video/mp4": "mp4", "video/quicktime": "mov", "application/pdf": "pdf", "text/plain": "txt", "text/html": "html", "application/json": "json", npz: "npz" }; if (this.content_type in e) return e[this.content_type]; if (_) try { const r = require("mime-types").extension(this.content_type); if (r) return r; } catch { } } return this.file_name && this.file_name.includes(".") && ((t = this.file_name.split(".").pop()) == null ? void 0 : t.toLowerCase()) || null; } /** * Get the filename. */ getFileName() { return this.file_name; } /** * Set the filename. */ setFileName(t) { this.file_name = t; } /** * Get the content type. */ getContentType() { return this.content_type; } /** * Set the content type. */ setContentType(t) { this.content_type = t; } /** * Read raw file data. * * @returns ArrayBuffer containing the file data */ read() { return this._ensureContent(), this._content; } /** * Check if the file is empty. * * @returns Boolean indicating if the file has content */ isEmpty() { return !this._content || this._content.byteLength === 0; } /** * Get info about the file. * * @returns Object with file information */ getInfo() { return { fileName: this.file_name, contentType: this.content_type, size: this.fileSize(), extension: this.extension }; } /** * Detect MIME type for the file based on file extension. * Updates the content_type property. * * @private */ _setContentTypeFromFileName() { var t; if (!this.file_name) return; const e = (t = this.file_name.split(".").pop()) == null ? void 0 : t.toLowerCase(); if (!e) return; if (_) try { const s = require("mime-types").lookup(this.file_name); if (s) { this.content_type = s; return; } } catch { } const r = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp", svg: "image/svg+xml", mp3: "audio/mpeg", wav: "audio/wav", ogg: "audio/ogg", mp4: "video/mp4", mov: "video/quicktime", pdf: "application/pdf", txt: "text/plain", html: "text/html", htm: "text/html", json: "application/json", js: "application/javascript", css: "text/css", xml: "application/xml", zip: "application/zip" }; e in r && (this.content_type = r[e]); } /** * Parse a base64 data URI into content and media type. * * @param data - Base64 string, potentially with data URI prefix * @returns Object containing the parsed data and media type * @private */ _parseBase64Uri(t) { if (t.startsWith("data:")) { const [e, r] = t.split(",", 2), s = e.match(/^data:([^;,]+)/), i = s ? s[1] : null; return { data: r, mediaType: i }; } return { data: t, mediaType: null }; } /** * Ensure content exists before operating on it. * * @private */ _ensureContent() { if (!this._content) throw new Error("No content available. Load content first using fromFile, fromUrl, etc."); } /** * Check if an object is a Buffer. * * @param obj - Object to check * @returns Whether the object is a Buffer * @private */ _isBuffer(t) { return _ && Buffer.isBuffer(t); } /** * Decode base64 string in Node.js environment. * * @param base64 - Base64 string to decode * @returns ArrayBuffer containing the decoded data * @private */ _decodeBase64NodeJs(t) { const e = Buffer.from(t, "base64"); return this._bufferToArrayBuffer(e); } /** * Decode base64 string in browser environment. * * @param base64 - Base64 string to decode * @returns ArrayBuffer containing the decoded data * @private */ _decodeBase64Browser(t) { const e = atob(t), r = new Uint8Array(e.length); for (let s = 0; s < e.length; s++) r[s] = e.charCodeAt(s); return r.buffer; } /** * Convert a Node.js Buffer to an ArrayBuffer. * * @param buffer - Buffer to convert * @returns ArrayBuffer containing the data * @private */ _bufferToArrayBuffer(t) { if (typeof SharedArrayBuffer < "u" && t.buffer instanceof SharedArrayBuffer) { const e = new ArrayBuffer(t.byteLength); return new Uint8Array(e).set(new Uint8Array(t)), e; } else return t.buffer.slice(t.byteOffset, t.byteOffset + t.byteLength); } } class F extends p { /** * Creates a new ImageFile instance. * * @param file_name - Default filename to use * @param content_type - Default content type to use (defaults to image/png) */ constructor(t = "image", e = "image/png") { super(t, e); } /** * Factory method to create an ImageFile from any supported data type. * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to an ImageFile instance */ static async create(t) { if (t == null) throw new Error("Cannot create ImageFile from null or undefined data"); return new F().fromAny(t); } /** * Override fromAny to ensure the content type is an image type. * * @param data - Data to load * @returns Promise resolving to an ImageFile instance */ async fromAny(t) { if (t instanceof F) return t; if (t instanceof p && !(t instanceof F)) { if (t.isEmpty()) throw new Error("Cannot create ImageFile from empty MediaFile"); return this.file_name = t.getFileName() || "image", this.content_type = t.getContentType(), this._content = t.read(), this._validateImageContentType(), this; } const e = await super.fromAny(t); return e.file_name = e.file_name || "image", e._validateImageContentType(), e; } /** * Creates an HTML image element from the image data. * * @param options - Optional image element attributes (width, height, alt, className) * @returns HTML string containing an image element */ toImageElement(t = {}) { if (typeof window > "u") throw new Error("Image elements are only available in browser environments"); this._ensureContent(); const e = this.toBase64(), { width: r, height: s, alt: i = "", className: o = "" } = t, l = r ? ` width="${r}"` : "", h = s ? ` height="${s}"` : "", c = o ? ` class="${o}"` : ""; return `<img src="${e}" alt="${i}"${l}${h}${c}>`; } /** * Create an actual DOM Image element (browser only). * * @param options - Optional image element attributes * @returns HTMLImageElement that can be added to the DOM */ toDOMImageElement(t = {}) { if (typeof window > "u") throw new Error("DOM Image elements are only available in browser environments"); this._ensureContent(); const e = this.toBlob(), r = URL.createObjectURL(e), s = new Image(); return t.width && (s.width = t.width), t.height && (s.height = t.height), t.alt && (s.alt = t.alt), t.className && (s.className = t.className), s.src = r, s.addEventListener("load", () => { setTimeout(() => URL.revokeObjectURL(r), 1e3); }), s; } /** * Get image dimensions (browser only). * * @returns Promise resolving to an object with width and height */ async getDimensions() { if (typeof window > "u") throw new Error("Getting image dimensions is only available in browser environments"); return new Promise((t, e) => { const r = new Image(); r.onload = () => { t({ width: r.naturalWidth, height: r.naturalHeight }); }, r.onerror = () => { e(new Error("Failed to load image for dimension calculation")); }; const s = this.toBlob(), i = URL.createObjectURL(s); r.src = i, r.addEventListener("load", () => { URL.revokeObjectURL(i); }, { once: !0 }); }); } /** * Validate that the content type is an image type. * If not, attempt to correct it based on file extension. * * @private */ _validateImageContentType() { var t; if (this.content_type.startsWith("image/")) return; const e = (t = this.extension) == null ? void 0 : t.toLowerCase(); if (e && e in E) { this.content_type = E[e]; return; } this._content && this._detectImageFormat(); } /** * Attempt to detect image format from file header. * Updates content_type if a format is detected. * * @private */ _detectImageFormat() { const t = new Uint8Array(this._content).slice(0, 12); if (t[0] === 255 && t[1] === 216 && t[2] === 255) { this.content_type = E.jpeg; return; } if (t[0] === 137 && t[1] === 80 && t[2] === 78 && t[3] === 71 && t[4] === 13 && t[5] === 10 && t[6] === 26 && t[7] === 10) { this.content_type = E.png; return; } if (t[0] === 71 && t[1] === 73 && t[2] === 70 && t[3] === 56 && (t[4] === 55 || t[4] === 57) && t[5] === 97) { this.content_type = E.gif; return; } if (t[0] === 82 && t[1] === 73 && t[2] === 70 && t[3] === 70 && t[8] === 87 && t[9] === 69 && t[10] === 66 && t[11] === 80) { this.content_type = E.webp; return; } if (this._content.byteLength > 100 && new TextDecoder().decode(new Uint8Array(this._content.slice(0, 100))).indexOf("<svg") !== -1) { this.content_type = E.svg; return; } this.content_type = E.png; } } class S extends p { /** * Creates a new AudioFile instance. * * @param file_name - Default filename to use * @param content_type - Default content type to use (defaults to audio/mpeg) */ constructor(t = "audio", e = "audio/wav") { super(t, e); } /** * Factory method to create an AudioFile from any supported data type. * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to an AudioFile instance */ static async create(t) { if (t == null) throw new Error("Cannot create AudioFile from null or undefined data"); return new S().fromAny(t); } /** * Override fromAny to ensure the content type is an audio type. * * @param data - Data to load * @returns Promise resolving to an AudioFile instance */ async fromAny(t) { if (t instanceof S) return t; if (t instanceof p && !(t instanceof S)) { if (t.isEmpty()) throw new Error("Cannot create AudioFile from empty MediaFile"); return this.file_name = t.getFileName() || "audio", this.content_type = t.getContentType(), this._content = t.read(), this._validateAudioContentType(), this; } const e = await super.fromAny(t); return e.file_name = e.file_name || "audio", e._validateAudioContentType(), e; } /** * Creates an HTML audio element from the audio data. * * @returns HTMLAudioElement that can be used for playback */ toAudioElement() { if (typeof window > "u") throw new Error("Audio elements are only available in browser environments"); this._ensureContent(); const t = this.toBlob(), e = URL.createObjectURL(t), r = new Audio(e); return r.addEventListener("canplaythrough", () => { setTimeout(() => URL.revokeObjectURL(e), 1e3); }), r; } /** * Play the audio (browser only). * * @returns Promise that resolves when audio playback starts */ async play() { if (typeof window > "u") throw new Error("Audio playback is only available in browser environments"); const t = this.toAudioElement(); return new Promise((e, r) => { t.addEventListener("play", () => e()), t.addEventListener("error", (s) => r(new Error(`Audio playback error: ${s}`))), t.play().catch(r); }); } /** * Get duration of the audio file in seconds (browser only). * * @returns Promise resolving to the duration in seconds */ async getDuration() { if (typeof window > "u") throw new Error("Getting audio duration is only available in browser environments"); const t = this.toAudioElement(); return new Promise((e) => { if (t.duration && !isNaN(t.duration)) { e(t.duration); return; } t.addEventListener("loadedmetadata", () => { e(t.duration); }); }); } /** * Create an embedded HTML audio player. * * @param options - Options for the audio player (controls, autoplay, loop) * @returns HTML string containing an audio element */ toHTMLPlayer(t = {}) { const e = this.toBase64(), { controls: r = !0, autoplay: s = !1, loop: i = !1 } = t; return `<audio src="${e}" ${r ? "controls" : ""} ${s ? "autoplay" : ""} ${i ? "loop" : ""}> Your browser does not support the audio element. </audio>`; } /** * Validate that the content type is an audio type. * If not, attempt to correct it based on file extension. * * @private */ _validateAudioContentType() { var t; if (this.content_type.startsWith("audio/")) return; const e = (t = this.extension) == null ? void 0 : t.toLowerCase(); if (e && e in b) { this.content_type = b[e]; return; } this._content && this._detectAudioFormat(); } /** * Attempt to detect audio format from file header. * Updates content_type if a format is detected. * * @private */ _detectAudioFormat() { const t = new Uint8Array(this._content).slice(0, 12); if (t[0] === 73 && t[1] === 68 && t[2] === 51) { this.content_type = b.mp3; return; } if (t[0] === 255 && (t[1] & 224) === 224) { this.content_type = b.mp3; return; } if (t[0] === 82 && t[1] === 73 && t[2] === 70 && t[3] === 70 && t[8] === 87 && t[9] === 65 && t[10] === 86 && t[11] === 69) { this.content_type = b.wav; return; } if (t[0] === 79 && t[1] === 103 && t[2] === 103 && t[3] === 83) { this.content_type = b.ogg; return; } if (t[0] === 102 && t[1] === 76 && t[2] === 97 && t[3] === 67) { this.content_type = b.flac; return; } this.content_type = b.mp3; } } class R extends p { /** * Creates a new VideoFile instance. * * @param file_name - Default filename to use * @param content_type - Default content type to use (defaults to video/mp4) */ constructor(t = "video", e = "video/mp4") { super(t, e); } /** * Factory method to create a VideoFile from any supported data type. * * @param data - Data to load (file path, URL, base64 string, etc.) * @returns Promise resolving to a VideoFile instance */ static async create(t) { if (t == null) throw new Error("Cannot create VideoFile from null or undefined data"); return new R().fromAny(t); } /** * Override fromAny to ensure the content type is a video type. * * @param data - Data to load * @returns Promise resolving to a VideoFile instance */ async fromAny(t) { if (t instanceof R) return t; if (t instanceof p && !(t instanceof R)) { if (t.isEmpty()) throw new Error("Cannot create VideoFile from empty MediaFile"); return this.file_name = t.getFileName() || "video", this.content_type = t.getContentType(), this._content = t.read(), this._validateVideoContentType(), this; } const e = await super.fromAny(t); return e.file_name = e.file_name || "video", e._validateVideoContentType(), e; } /** * Creates an HTML video element from the video data. * * @returns HTMLVideoElement that can be used for playback */ toVideoElement() { if (typeof window > "u") throw new Error("Video elements are only available in browser environments"); this._ensureContent(); const t = this.toBlob(), e = URL.createObjectURL(t), r = document.createElement("video"); return r.src = e, r.addEventListener("loadedmetadata", () => { setTimeout(() => URL.revokeObjectURL(e), 1e3); }), r; } /** * Play the video (browser only). * * @returns Promise that resolves when video playback starts */ async play() { if (typeof window > "u") throw new Error("Video playback is only available in browser environments"); const t = this.toVideoElement(); return new Promise((e, r) => { t.addEventListener("play", () => e()), t.addEventListener("error", (s) => r(new Error(`Video playback error: ${s}`))), t.play().catch(r); }); } /** * Get duration of the video file in seconds (browser only). * * @returns Promise resolving to the duration in seconds */ async getDuration() { if (typeof window > "u") throw new Error("Getting video duration is only available in browser environments"); const t = this.toVideoElement(); return new Promise((e) => { if (t.duration && !isNaN(t.duration)) { e(t.duration); return; } t.addEventListener("loadedmetadata", () => { e(t.duration); }); }); } /** * Get dimensions of the video (width and height). * * @returns Promise resolving to an object with width and height properties */ async getDimensions() { if (typeof window > "u") throw new Error("Getting video dimensions is only available in browser environments"); const t = this.toVideoElement(); return new Promise((e) => { if (t.videoWidth && t.videoHeight) { e({ width: t.videoWidth, height: t.videoHeight }); return; } t.addEventListener("loadedmetadata", () => { e({ width: t.videoWidth, height: t.videoHeight }); }); }); } /** * Create a thumbnail from the video at a specific time point. * * @param timeSeconds - Time in seconds for the thumbnail (defaults to 0) * @returns Promise resolving to a Blob containing the thumbnail image */ async createThumbnail(t = 0) { if (typeof window > "u") throw new Error("Creating thumbnails is only available in browser environments"); const e = this.toVideoElement(); return new Promise((r, s) => { e.addEventListener("loadedmetadata", async () => { try { e.currentTime = t, await new Promise((l) => { const h = () => { e.removeEventListener("seeked", h), l(); }; e.addEventListener("seeked", h); }); const i = document.createElement("canvas"); i.width = e.videoWidth, i.height = e.videoHeight; const o = i.getContext("2d"); if (!o) throw new Error("Failed to get canvas context"); o.drawImage(e, 0, 0, i.width, i.height), i.toBlob((l) => { l ? r(l) : s(new Error("Failed to create thumbnail blob")); }, "image/jpeg", 0.95); } catch (i) { s(i); } }), e.addEventListener("error", (i) => { s(new Error(`Video loading error: ${i}`)); }); }); } /** * Create an embedded HTML video player. * * @param options - Options for the video player * @returns HTML string containing a video element */ toHtmlPlayer(t = {}) { const e = this.toBase64(), { controls: r = !0, autoplay: s = !1, loop: i = !1, muted: o = !1, width: l, height: h, poster: c } = t; return `<video src="${e}" ${r ? "controls" : ""} ${s ? "autoplay" : ""} ${i ? "loop" : ""} ${o ? "muted" : ""} ${l ? `width="${l}"` : ""} ${h ? `height="${h}"` : ""} ${c ? `poster="${c}"` : ""}> Your browser does not support the video element. </video>`; } /** * Validate that the content type is a video type. * If not, attempt to correct it based on file extension. * * @private */ _validateVideoContentType() { var t; if (this.content_type.startsWith("video/")) return; const e = (t = this.extension) == null ? void 0 : t.toLowerCase(); if (e && e in w) { this.content_type = w[e]; return; } this._content && this._detectVideoFormat(); } /** * Attempt to detect video format from file header. * Updates content_type if a format is detected. * * @private */ _detectVideoFormat() { const t = new Uint8Array(this._content).slice(0, 16); if (t[4] === 102 && t[5] === 116 && t[6] === 121 && t[7] === 112) { this.content_type = w.mp4; return; } if (t[4] === 119 && t[5] === 105 && t[6] === 100 && t[7] === 101 || t[4] === 109 && t[5] === 100 && t[6] === 97 && t[7] === 116 || t[4] === 102 && t[5] === 114 && t[6] === 101 && t[7] === 101 || t[4] === 112 && t[5] === 110 && t[6] === 111 && t[7] === 116 || t[4] === 115 && t[5] === 107 && t[6] === 105 && t[7] === 112 || t[4] === 109 && t[5] === 111 && t[6] === 111 && t[7] === 118) { this.content_type = w.mov; return; } if (t[0] === 26 && t[1] === 69 && t[2] === 223 && t[3] === 163) { this.content_type = w.webm; return; } if (t[0] === 82 && t[1] === 73 && t[2] === 70 && t[3] === 70 && t[8] === 65 && t[9] === 86 && t[10] === 73 && t[11] === 32) { this.content_type = w.avi; return; } if (t[0] === 70 && t[1] === 76 && t[2] === 86) { this.content_type = w.flv; return; } if (t[4] === 102 && t[5] === 116 && t[6] === 121 && t[7] === 112 && t[8] === 51 && t[9] === 103 && t[10] === 112) { this.content_type = w["3gp"]; return; } this.content_type = w.mp4; } } const I = {}; I.default = p; I.image = F; I.audio = S; I.video = R; I.media = p; typeof window < "u" && (window.MediaFile = p, window.ImageFile = F, window.AudioFile = S, window.AudioFile = R); typeof module < "u" && typeof module.exports < "u" && (module.exports = { MediaFile: p, ImageFile: F, AudioFile: S, VideoFile: R, MediaFileFactory: L }); class ct { // 60 seconds timeout for uploads /** * Create a new FastCloud instance * @param config FastCloud configuration */ constructor(t) { a(this, "uploadEndpoint"); a(this, "apiKey"); a(this, "defaultTimeout", 6e4); this.uploadEndpoint = t.uploadEndpoint || "https://api.socaity.ai/sdk/v1/files", this.apiKey = t.apiKey; } setApiKey(t) { this.apiKey = t; } /** * Get authentication headers for requests * @returns Headers object with authentication */ getAuthHeaders() { return { Authorization: `Bearer ${this.apiKey}` }; } /** * Process the upload response to extract file URLs * @param response Response from the upload endpoint * @returns Array of temporary upload URLs */ async processUploadResponse(t) { if (t.status === 401) throw new Error("Unauthorized: Invalid API key"); if (!t.ok) throw console.error("Failed to get temporary upload URL:", t), new Error(`Failed to get temporary upload URL: ${t.status} ${t.statusText}`); try { const e = await t.text(), r = JSON.parse(e); return Array.isArray(r) ? r : [r]; } catch (e) { throw console.error("Error parsing response:", e), new Error("Failed to parse response body as JSON"); } } /** * Upload a file to a temporary URL * @param sasUrl Temporary URL for uploading * @param file File to upload */ async uploadToTemporaryUrl(t, e) { const r = { "x-ms-blob-type": "BlockBlob", "x-ms-if-none-match": "*" }, s = e instanceof p ? await e.toArrayBuffer() : e, i = await fetch(t, { method: "PUT", headers: r, body: s }); if (i.status !== 201) throw new Error(`Failed to upload to temporary URL ${t}. Response: ${i.statusText}`); } /** * Upload a single file * @param file File to upload * @returns the URLs of the uploaded files. (If one file is uploaded, the return value is an array with one URL) */ async upload(t) { const e = Array.isArray(t) ? t : [t], r = e.map((c) => c.extension).filter((c) => c !== null), s = { "Content-Type": "application/json", ...this.getAuthHeaders() }, i = await fetch(this.uploadEndpoint, { method: "POST", headers: s, body: JSON.stringify({ n_files: e.length, file_extensions: r.length > 0 ? r : void 0 }), signal: AbortSignal.timeout(this.defaultTimeout) }), o = await this.processUploadResponse(i), l = o.map( (c, v) => this.uploadToTemporaryUrl(c, e[v]) ); return await Promise.all(l), o.map((c) => c.split("?")[0]); } /** * Download a file from a URL * @param url URL to download from * @param savePath Optional path to save the file to * @returns MediaFile object or save path if specified */ async download(t, e) { const r = await new p(t).fromUrl(t, this.getAuthHeaders()); return e ? (await r.save(e), e) : r; } } class Z { constructor() { a(this, "config"); a(this, "uploadFileThresholdMB", 1); a(this, "maxFileUploadLimitMB", 1e3); a(this, "fastCloud"); a(this, "abortController"); a(this, "responseParser"); this.config = T.getInstance(), this.abortController = new AbortController(), this.responseParser = new rt(), this.fastCloud = new ct({ uploadEndpoint: `${this.config.baseUrl}/sdk/files`, apiKey: this.config.apiKey ? this.config.apiKey : "" }); } /** * Check if a parameter is a file type based on parameter definition and value */ isFileType(t, e) { const r = ["file", "image", "audio", "video"]; if (typeof t.type == "string") { const s = this.getBaseType(t.type); if (r.includes(s)) return !0; } return Array.isArray(t.type) && t.type.some((i) => { const o = this.getBaseType(i); return r.includes(o); }) || e instanceof p ? !0 : e == null ? !1 : !!(e instanceof File || e instanceof Blob || typeof e == "string" && B(e)); } /** * Extract base type from List[type] or type string */ getBaseType(t) { if (!t) return "string"; const e = t.match(/^List\[(.+)\]$/i); return e && e[1] ? e[1].toLowerCase() : t.toLowerCase(); } /** * Format request parameters similar to Python's format_request_params * @param endpoint Endpoint metadata * @param data Request parameters * @returns Organized request data */ async formatRequestParams(t, e) { const r = { queryParams: {}, bodyParams: {}, fileParams: {}, headers: {}, url: "" }; if (!t.parameters || t.parameters.length === 0) return r.url = this.buildRequestUrl(t.path, r.queryParams), r; for (const s of t.parameters) { const i = e[s.name] ?? s.default; if (i === void 0 && s.required) throw new Error(`Required parameter '${s.name}' is missing`); if (i === void 0) continue; if (this.isFileType(s, i)) { if (i == null) { r.bodyParams[s.name] = null; continue; } if (typeof i == "string" && B(i)) r.fileParams[s.name] = i; else try { const l = i instanceof p ? i : await L.create(i); l instanceof p && (r.fileParams[s.name] = l); } catch (l) { console.warn(`Failed to convert ${s.name} to MediaFile:`, l), s.location === "query" ? r.queryParams[s.name] = i : r.bodyParams[s.name] = i; } } else s.location === "query" ? r.queryParams[s.name] = i : r.bodyParams[s.name] = i; } return r.fileParams = await this.processFileParams(r.fileParams), r.url = this.buildRequestUrl(t.path, r.queryParams), r; } /** * Process file parameters - handle uploads and conversions */ async processFileParams(t) { const e = {}; let r = 0; const s = {}; for (const [i, o] of Object.entries(t)) typeof o == "string" && B(o) ? e[i] = o : o instanceof p && (s[i] = o, r += o.fileSize("mb")); if (r > this.maxFileUploadLimitMB) throw new Error(`Total file size exceeds maximum limit of ${this.maxFileUploadLimitMB}MB`); if (r > this.uploadFileThresholdMB) {