UNPKG

@tsavo/creatify-api-ts

Version:

TypeScript client for the Creatify AI API

228 lines (207 loc) 7.9 kB
import { CreatifyApiOptions } from '../types'; import { Avatar } from '../types'; import { ICreatifyApiClient } from '../types/api-client'; import { apiClientFactory } from '../client-factory'; /** * Client for interacting with the Creatify AI Avatar API * @see https://creatify.mintlify.app/api-reference/lipsync */ export class AvatarApi { private client: ICreatifyApiClient; /** * Create a new AvatarApi instance * @param options API client options * @param clientFactory Optional factory for creating API clients (useful for testing) */ constructor(options: CreatifyApiOptions, clientFactory = apiClientFactory) { this.client = clientFactory.createClient(options); } /** * Get a list of all available avatars * @returns Promise resolving to an array of avatar information * @see https://creatify.mintlify.app/api-reference/personas/get-apipersonas */ async getAvatars(filters?: { age_range?: 'child' | 'teen' | 'adult' | 'senior'; gender?: 'm' | 'f' | 'nb'; location?: 'outdoor' | 'fantasy' | 'indoor' | 'other'; style?: 'selfie' | 'presenter' | 'other'; }): Promise<Avatar.AvatarInfo[]> { try { const avatars = await this.client.get<Avatar.AvatarInfo[]>('/api/personas/', filters); // Ensure avatars is an array if (!Array.isArray(avatars)) { return []; } // Add avatar_id property for backward compatibility and explicitly add a name property return avatars.map(avatar => ({ ...avatar, avatar_id: avatar.id, // Force the name property to be 'Avatar ID' if it's missing, empty or undefined name: avatar.name && avatar.name.trim() ? avatar.name : `Avatar ${avatar.id}`, })); } catch (error) { console.error('Error fetching avatars:', error); return []; } } /** * Get a list of available avatars with pagination * @param page Page number (starts from 1) * @param limit Number of items per page * @param filters Optional filtering parameters * @returns Promise resolving to paginated avatar information * @see https://creatify.mintlify.app/api-reference/personas/get-apipersonas-paginated */ async getAvatarsPaginated( page: number = 1, limit: number = 20, filters?: { age_range?: 'child' | 'teen' | 'adult' | 'senior'; gender?: 'm' | 'f' | 'nb'; location?: 'outdoor' | 'fantasy' | 'indoor' | 'other'; style?: 'selfie' | 'presenter' | 'other'; } ): Promise<{ count: number; next: string | null; previous: string | null; results: Avatar.AvatarInfo[]; }> { return this.client.get('/api/personas-paginated/', { page, limit, ...filters, }); } /** * Get a list of all available voices * @returns Promise resolving to an array of voice information * @see https://creatify.mintlify.app/api-reference/voices/get-apivoices */ async getVoices(): Promise<Avatar.VoiceInfo[]> { try { const voices = await this.client.get<Avatar.VoiceInfo[]>('/api/voices/'); // Ensure voices is an array if (!Array.isArray(voices)) { return []; } // Process voice data to handle different API response formats return voices.map(voice => { // Create a normalized version of each voice with consistent properties const normalizedVoice: Avatar.VoiceInfo = { // Ensure ID is available in a consistent field id: voice.id || voice.voice_id || '', voice_id: voice.voice_id || voice.id || '', name: voice.name || 'Unnamed Voice', language: voice.language || '', gender: voice.gender || '', accents: voice.accents || [], // Extract preview URL from the first accent if not directly available preview_url: voice.preview_url || (voice.accents && voice.accents.length > 0 && voice.accents[0].preview_url) || '', }; return normalizedVoice; }); } catch (error) { console.error('Error fetching voices:', error); return []; } } /** * Create a lipsync video with an AI avatar speaking the provided text * @param params Parameters for the lipsync video generation * @returns Promise resolving to the lipsync task response * @see https://creatify.mintlify.app/api-reference/lipsync */ async createLipsync(params: Avatar.LipsyncParams): Promise<Avatar.LipsyncResponse> { try { return await this.client.post<Avatar.LipsyncResponse>('/api/lipsyncs/', params); } catch (error) { console.error('Error creating lipsync:', error); throw error; } } /** * Get the status and result of a lipsync task * @param id ID of the lipsync task * @returns Promise resolving to the lipsync task status and result * @see https://creatify.mintlify.app/api-reference/lipsync */ async getLipsync(id: string): Promise<Avatar.LipsyncResultResponse> { try { return await this.client.get<Avatar.LipsyncResultResponse>(`/api/lipsyncs/${id}/`); } catch (error) { console.error(`Error fetching lipsync result for ID ${id}:`, error); // Return a default response to prevent crashes return { id, status: 'error', error_message: error instanceof Error ? error.message : 'An error occurred with the API request', } as Avatar.LipsyncResultResponse; } } /** * Get all lipsync tasks * @returns Promise resolving to an array of lipsync tasks * @see https://creatify.mintlify.app/api-reference/lipsync */ async getLipsyncs(): Promise<Avatar.LipsyncResultResponse[]> { try { const results = await this.client.get<Avatar.LipsyncResultResponse[]>('/api/lipsyncs/'); return Array.isArray(results) ? results : []; } catch (error) { console.error('Error fetching lipsync tasks:', error); return []; } } /** * Create a multi-avatar lipsync video with multiple AI avatars speaking * @param params Parameters for the multi-avatar lipsync video generation * @returns Promise resolving to the lipsync task response * @see https://creatify.mintlify.app/api-reference/lipsync-multi-avatar */ async createMultiAvatarLipsync( params: Avatar.MultiAvatarLipsyncParams ): Promise<Avatar.LipsyncResponse> { try { return await this.client.post<Avatar.LipsyncResponse>('/api/lipsyncs/multi_avatar/', params); } catch (error) { console.error('Error creating multi-avatar lipsync:', error); throw error; } } /** * Create a lipsync video and wait for it to complete * @param params Parameters for the lipsync video generation * @param pollInterval How often to check status in ms (default 2000) * @param maxAttempts Maximum number of polling attempts (default 30) * @returns Promise resolving to the completed lipsync task */ async createAndWaitForLipsync( params: Avatar.LipsyncParams, pollInterval: number = 2000, maxAttempts: number = 30 ): Promise<Avatar.LipsyncResultResponse> { // Create the lipsync task const response = await this.createLipsync(params); // Poll for completion let attempts = 0; let result = await this.getLipsync(response.id); while (attempts < maxAttempts && result.status !== 'done' && result.status !== 'error') { // Wait for the specified interval await new Promise(resolve => setTimeout(resolve, pollInterval)); // Check the status again result = await this.getLipsync(response.id); attempts++; } // Check if we reached max attempts without completion if (attempts >= maxAttempts && result.status !== 'done' && result.status !== 'error') { throw new Error(`Lipsync task ${response.id} did not complete within the timeout period`); } return result; } }