Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { heygenAuth } from '../common/auth';
|
||||
import { heygenApiCall } from '../common/client';
|
||||
import {
|
||||
folderDropdown,
|
||||
brandVoiceDropdown,
|
||||
templateDropdown,
|
||||
templateVariables,
|
||||
} from '../common/props';
|
||||
import { isNil } from '@activepieces/shared';
|
||||
|
||||
export const createVideoFromTemplateAction = createAction({
|
||||
auth: heygenAuth,
|
||||
name: 'create-video-from-template',
|
||||
displayName: 'Create Video from Template',
|
||||
description: 'Create a video using a selected template.',
|
||||
props: {
|
||||
templateId: templateDropdown,
|
||||
title: Property.ShortText({
|
||||
displayName: 'Video Title',
|
||||
required: true,
|
||||
description: 'Title of the generated video.',
|
||||
}),
|
||||
caption: Property.Checkbox({
|
||||
displayName: 'Enable Captions',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
includeGif: Property.Checkbox({
|
||||
displayName: 'Include GIF Preview',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
enableSharing: Property.Checkbox({
|
||||
displayName: 'Enable Public Sharing',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
folderId: folderDropdown,
|
||||
brandVoiceId: brandVoiceDropdown,
|
||||
callbackUrl: Property.ShortText({
|
||||
displayName: 'Callback URL',
|
||||
required: false,
|
||||
description: 'Webhook URL to notify when video rendering is complete.',
|
||||
}),
|
||||
dimensionWidth: Property.Number({
|
||||
displayName: 'Video Width',
|
||||
required: false,
|
||||
defaultValue: 1280,
|
||||
}),
|
||||
dimensionHeight: Property.Number({
|
||||
displayName: 'Video Height',
|
||||
required: false,
|
||||
defaultValue: 720,
|
||||
}),
|
||||
variables: templateVariables,
|
||||
},
|
||||
async run({ propsValue, auth }) {
|
||||
const {
|
||||
templateId,
|
||||
title,
|
||||
caption,
|
||||
includeGif,
|
||||
enableSharing,
|
||||
folderId,
|
||||
brandVoiceId,
|
||||
callbackUrl,
|
||||
dimensionWidth,
|
||||
dimensionHeight,
|
||||
} = propsValue;
|
||||
|
||||
const inputVariables = propsValue.variables ?? {};
|
||||
|
||||
const template = await heygenApiCall<{
|
||||
data: {
|
||||
variables: { [x: string]: { type: string; name: string; properties: Record<string, any> } };
|
||||
};
|
||||
}>({
|
||||
apiKey: auth as unknown as string,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/template/${templateId}`,
|
||||
apiVersion: 'v2',
|
||||
});
|
||||
|
||||
const templateVariables = template.data.variables;
|
||||
const formattedVariables: Record<string, any> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(inputVariables)) {
|
||||
if (isNil(value) || value === '') continue;
|
||||
|
||||
const variable = templateVariables[key];
|
||||
if (!variable) continue;
|
||||
|
||||
const { type, name, properties } = variable;
|
||||
|
||||
const base = { name, type };
|
||||
|
||||
switch (type) {
|
||||
case 'text':
|
||||
formattedVariables[key] = {
|
||||
...base,
|
||||
properties: { content: value },
|
||||
};
|
||||
break;
|
||||
case 'image':
|
||||
case 'video':
|
||||
case 'audio':
|
||||
formattedVariables[key] = {
|
||||
...base,
|
||||
properties: { ...properties, url: value },
|
||||
};
|
||||
break;
|
||||
case 'character':
|
||||
formattedVariables[key] = {
|
||||
...base,
|
||||
properties: { ...properties, character_id: value },
|
||||
};
|
||||
break;
|
||||
case 'voice':
|
||||
formattedVariables[key] = {
|
||||
...base,
|
||||
properties: { ...properties, voice_id: value },
|
||||
};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const body: Record<string, any> = {
|
||||
template_id: templateId,
|
||||
title,
|
||||
caption: caption === true,
|
||||
include_gif: includeGif === true,
|
||||
enable_sharing: enableSharing === true,
|
||||
};
|
||||
|
||||
if (folderId) body['folder_id'] = folderId;
|
||||
if (brandVoiceId) body['brand_voice_id'] = brandVoiceId;
|
||||
if (callbackUrl) body['callback_url'] = callbackUrl;
|
||||
|
||||
if (dimensionWidth && dimensionHeight) {
|
||||
body['dimension'] = {
|
||||
width: dimensionWidth,
|
||||
height: dimensionHeight,
|
||||
};
|
||||
}
|
||||
|
||||
if (Object.keys(formattedVariables || {}).length) {
|
||||
body['variables'] = formattedVariables;
|
||||
}
|
||||
|
||||
const response = await heygenApiCall({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: `/template/${templateId}/generate`,
|
||||
body,
|
||||
apiVersion: 'v2',
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { heygenAuth } from '../common/auth';
|
||||
import { heygenApiCall } from '../common/client';
|
||||
|
||||
export const retrieveTranslatedVideoStatus = createAction({
|
||||
auth: heygenAuth,
|
||||
name: 'retrieve-translated-video-status',
|
||||
displayName: 'Retrieve Translated Video Status',
|
||||
description: 'Retrieves the status of a translated video.',
|
||||
props: {
|
||||
videoId: Property.ShortText({
|
||||
displayName: 'Video ID',
|
||||
required: true,
|
||||
description: 'The ID of the translated video to check the status for.',
|
||||
}),
|
||||
},
|
||||
async run({ propsValue, auth }) {
|
||||
const { videoId } = propsValue;
|
||||
|
||||
const response = await heygenApiCall({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/video_translate/${videoId}`,
|
||||
apiVersion: 'v2',
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { heygenApiCall } from '../common/client';
|
||||
import { heygenAuth } from '../common/auth';
|
||||
|
||||
export const retrieveVideoStatusAction = createAction({
|
||||
auth: heygenAuth,
|
||||
name: 'retrieve_video_status',
|
||||
displayName: 'Retrieve Video Status',
|
||||
description: 'Retrieve the status and details of a video using its ID.',
|
||||
props: {
|
||||
videoId: Property.ShortText({
|
||||
displayName: 'Video ID',
|
||||
description: 'The ID of the video to retrieve the status for.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run({ propsValue, auth }) {
|
||||
const { videoId } = propsValue;
|
||||
|
||||
const response = await heygenApiCall({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/video_status.get`,
|
||||
query: { video_id: videoId },
|
||||
apiVersion: 'v1',
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { heygenApiCall } from '../common/client';
|
||||
import { heygenAuth } from '../common/auth';
|
||||
|
||||
export const retrieveSharableVideoUrlAction = createAction({
|
||||
auth: heygenAuth,
|
||||
name: 'retrieve_sharable_video_url',
|
||||
displayName: 'Retrieve Sharable Video URL',
|
||||
description: 'Generates a public URL for a video, allowing it to be shared and accessed publicly.',
|
||||
props: {
|
||||
videoId: Property.ShortText({
|
||||
displayName: 'Video ID',
|
||||
description: 'The ID of the video to generate a shareable URL for.',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run({ propsValue, auth }) {
|
||||
const { videoId } = propsValue;
|
||||
|
||||
const response = await heygenApiCall({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/video/share',
|
||||
body: { video_id: videoId },
|
||||
apiVersion: 'v1',
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { heygenApiCall } from '../common/client';
|
||||
import { heygenAuth } from '../common/auth';
|
||||
import { brandVoiceDropdown, supportedLanguagesDropdown } from '../common/props';
|
||||
|
||||
export const translateVideoAction = createAction({
|
||||
auth: heygenAuth,
|
||||
name: 'translate_video',
|
||||
displayName: 'Translate Video',
|
||||
description: 'Translate a video into 175+ languages with natural voice and lip-sync.',
|
||||
props: {
|
||||
videoUrl: Property.ShortText({
|
||||
displayName: 'Video URL',
|
||||
required: true,
|
||||
description:
|
||||
'URL of the video file to be translated. Supports direct URLs, Google Drive, and YouTube.',
|
||||
}),
|
||||
title: Property.ShortText({
|
||||
displayName: 'Title',
|
||||
required: false,
|
||||
description: 'Optional title of the translated video.',
|
||||
}),
|
||||
outputLanguage: supportedLanguagesDropdown,
|
||||
translateAudioOnly: Property.Checkbox({
|
||||
displayName: 'Translate Audio Only',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
description: 'Only translate the audio without modifying faces.',
|
||||
}),
|
||||
speakerNum: Property.Number({
|
||||
displayName: 'Number of Speakers',
|
||||
required: false,
|
||||
description: 'Number of speakers in the video (if applicable).',
|
||||
}),
|
||||
brandVoiceId: brandVoiceDropdown,
|
||||
|
||||
callbackId: Property.ShortText({
|
||||
displayName: 'Callback ID',
|
||||
required: false,
|
||||
description: 'Custom ID returned in webhook callback.',
|
||||
}),
|
||||
callbackUrl: Property.ShortText({
|
||||
displayName: 'Callback URL',
|
||||
required: false,
|
||||
description: 'URL to notify when translation is complete.',
|
||||
}),
|
||||
},
|
||||
async run({ propsValue, auth }) {
|
||||
const {
|
||||
videoUrl,
|
||||
title,
|
||||
outputLanguage,
|
||||
translateAudioOnly,
|
||||
speakerNum,
|
||||
callbackId,
|
||||
brandVoiceId,
|
||||
callbackUrl,
|
||||
} = propsValue;
|
||||
|
||||
const body: Record<string, unknown> = {
|
||||
video_url: videoUrl,
|
||||
output_language: outputLanguage,
|
||||
};
|
||||
|
||||
if (title) body['title'] = title;
|
||||
if (translateAudioOnly) body['translate_audio_only'] = translateAudioOnly;
|
||||
if (speakerNum) body['speaker_num'] = speakerNum;
|
||||
if (callbackId) body['callback_id'] = callbackId;
|
||||
if (brandVoiceId) body['brand_voice_id'] = brandVoiceId;
|
||||
if (callbackUrl) body['callback_url'] = callbackUrl;
|
||||
|
||||
const response = await heygenApiCall({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/video_translate',
|
||||
body,
|
||||
apiVersion: 'v2',
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
import { heygenAuth } from '../common/auth';
|
||||
|
||||
export const uploadAssetAction = createAction({
|
||||
auth: heygenAuth,
|
||||
name: 'upload_asset',
|
||||
displayName: 'Upload an Asset',
|
||||
description:
|
||||
'Upload media files (images, videos, or audio) to HeyGen. Supports JPEG, PNG, MP4, WEBM, and MPEG files.',
|
||||
props: {
|
||||
file: Property.File({
|
||||
displayName: 'File',
|
||||
description: 'The file to upload (JPEG, PNG, MP4, WEBM, or MPEG).',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { file } = context.propsValue;
|
||||
|
||||
const getContentType = (filename: string): string => {
|
||||
const extension = filename.toLowerCase().split('.').pop();
|
||||
switch (extension) {
|
||||
case 'jpg':
|
||||
case 'jpeg':
|
||||
return 'image/jpeg';
|
||||
case 'png':
|
||||
return 'image/png';
|
||||
case 'mp4':
|
||||
return 'video/mp4';
|
||||
case 'webm':
|
||||
return 'video/webm';
|
||||
case 'mpeg':
|
||||
case 'mpg':
|
||||
return 'audio/mpeg';
|
||||
default:
|
||||
throw new Error(`Unsupported file type: ${extension}`);
|
||||
}
|
||||
};
|
||||
|
||||
const contentType = getContentType(file.filename);
|
||||
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.POST,
|
||||
url: 'https://upload.heygen.com/v1/asset',
|
||||
headers: {
|
||||
'x-api-key': context.auth.secret_text,
|
||||
'Content-Type': contentType,
|
||||
},
|
||||
body: file.data,
|
||||
});
|
||||
|
||||
return response.body;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { PieceAuth } from '@activepieces/pieces-framework';
|
||||
import { heygenApiCall } from './client';
|
||||
|
||||
export const heygenAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
description: `You can obtain your API key by navigating to your Space Settings in HeyGen App.`,
|
||||
required: true,
|
||||
validate: async ({ auth }) => {
|
||||
try {
|
||||
await heygenApiCall({
|
||||
apiKey: auth as string,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/user/me',
|
||||
apiVersion: 'v1',
|
||||
});
|
||||
return { valid: true };
|
||||
} catch {
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Invalid API Key.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
httpClient,
|
||||
HttpMessageBody,
|
||||
HttpMethod,
|
||||
HttpRequest,
|
||||
QueryParams,
|
||||
} from '@activepieces/pieces-common';
|
||||
|
||||
export type HeygenApiCallParams = {
|
||||
apiKey: string;
|
||||
method: HttpMethod;
|
||||
resourceUri: string;
|
||||
query?: Record<string, string | number | string[] | undefined>;
|
||||
body?: unknown;
|
||||
apiVersion: 'v1' | 'v2';
|
||||
};
|
||||
|
||||
export const BASE_URL_V1 = 'https://api.heygen.com/v1';
|
||||
export const BASE_URL_V2 = 'https://api.heygen.com/v2';
|
||||
|
||||
export async function heygenApiCall<T extends HttpMessageBody>({
|
||||
apiKey,
|
||||
method,
|
||||
resourceUri,
|
||||
query,
|
||||
body,
|
||||
apiVersion,
|
||||
}: HeygenApiCallParams): Promise<T> {
|
||||
const qs: QueryParams = {};
|
||||
|
||||
if (query) {
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value !== null && value !== undefined) {
|
||||
qs[key] = String(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const url = (apiVersion === 'v1' ? BASE_URL_V1 : BASE_URL_V2) + resourceUri;
|
||||
|
||||
const request: HttpRequest = {
|
||||
method,
|
||||
url,
|
||||
headers: {
|
||||
'X-Api-Key': apiKey,
|
||||
},
|
||||
queryParams: qs,
|
||||
body,
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<T>(request);
|
||||
return response.body;
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { DynamicPropsValue, Property } from '@activepieces/pieces-framework';
|
||||
import { heygenApiCall } from './client';
|
||||
import { isNil } from '@activepieces/shared';
|
||||
import { heygenAuth } from './auth';
|
||||
|
||||
export const folderDropdown = Property.Dropdown({
|
||||
displayName: 'Folder',
|
||||
description: 'Select the folder to store the video.',
|
||||
required: false,
|
||||
refreshers: [],
|
||||
auth: heygenAuth,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first.',
|
||||
};
|
||||
}
|
||||
|
||||
const response = await heygenApiCall<{
|
||||
data: { folders: { id: string; name: string }[] };
|
||||
}>({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/folders',
|
||||
apiVersion: 'v1',
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.data.folders.map((folder) => ({
|
||||
label: folder.name,
|
||||
value: folder.id,
|
||||
})),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const brandVoiceDropdown = Property.Dropdown({
|
||||
auth: heygenAuth,
|
||||
displayName: 'Brand Voice',
|
||||
description: 'Select the Brand Voice to apply to the video.',
|
||||
required: false,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first.',
|
||||
};
|
||||
}
|
||||
|
||||
const response = await heygenApiCall<{
|
||||
data: { list: { id: string; name: string }[] };
|
||||
}>({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/brand_voice/list',
|
||||
apiVersion: 'v1',
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.data.list.map((voice) => ({
|
||||
label: voice.name,
|
||||
value: voice.id,
|
||||
})),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const templateDropdown = Property.Dropdown({
|
||||
auth: heygenAuth,
|
||||
displayName: 'Template',
|
||||
description: 'Select the template to generate the video.',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first.',
|
||||
};
|
||||
}
|
||||
|
||||
const response = await heygenApiCall<{
|
||||
data: { templates: { template_id: string; name: string; aspect_ratio: string }[] };
|
||||
}>({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/templates',
|
||||
apiVersion: 'v2',
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.data.templates.map((template) => ({
|
||||
label: template.name,
|
||||
value: template.template_id,
|
||||
})),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const supportedLanguagesDropdown = Property.Dropdown({
|
||||
auth: heygenAuth,
|
||||
displayName: 'Supported Language',
|
||||
description: 'Select the language for video translation.',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first.',
|
||||
};
|
||||
}
|
||||
|
||||
const response = await heygenApiCall<{ data: { languages: string[] } }>({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: '/video_translate/target_languages',
|
||||
apiVersion: 'v2',
|
||||
});
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: response.data.languages.map((lang) => ({
|
||||
label: lang,
|
||||
value: lang,
|
||||
})),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export const templateVariables = Property.DynamicProperties({
|
||||
auth: heygenAuth,
|
||||
displayName: 'Template Varriables',
|
||||
refreshers: ['templateId'],
|
||||
required: false,
|
||||
props: async ({ auth, templateId }) => {
|
||||
if (!auth || !templateId) return {};
|
||||
|
||||
const fields: DynamicPropsValue = {};
|
||||
|
||||
try {
|
||||
const response = await heygenApiCall<{
|
||||
data: { variables: { [x: string]: { type: string; name: string } } };
|
||||
}>({
|
||||
apiKey: auth.secret_text,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/template/${templateId}`,
|
||||
apiVersion: 'v2',
|
||||
});
|
||||
|
||||
const variables = response.data.variables;
|
||||
|
||||
if (!isNil(variables)) return {};
|
||||
|
||||
for (const [key, value] of Object.entries(response.data.variables)) {
|
||||
const fieldKey = key;
|
||||
const fieldType = value.type;
|
||||
|
||||
switch (fieldType) {
|
||||
case 'text':
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldKey,
|
||||
required: false,
|
||||
description: 'Provide text value.',
|
||||
});
|
||||
break;
|
||||
case 'image':
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldKey,
|
||||
required: false,
|
||||
description: 'Provide image URL.',
|
||||
});
|
||||
break;
|
||||
case 'video':
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldKey,
|
||||
required: false,
|
||||
description: 'Provide video URL.',
|
||||
});
|
||||
break;
|
||||
case 'audio':
|
||||
fields[fieldKey] = Property.ShortText({
|
||||
displayName: fieldKey,
|
||||
required: false,
|
||||
description: 'Provide audio URL.',
|
||||
});
|
||||
break;
|
||||
case 'character': {
|
||||
const characters = await heygenApiCall<{
|
||||
avatars: { avatar_name: string; avatar_id: string }[];
|
||||
talking_photos: {
|
||||
talking_photo_id: string;
|
||||
talking_photo_name: string;
|
||||
}[];
|
||||
}>({
|
||||
apiKey: auth as unknown as string,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/avatars`,
|
||||
apiVersion: 'v2',
|
||||
});
|
||||
|
||||
const options = [
|
||||
...characters.avatars.map((avatar) => ({
|
||||
label: avatar.avatar_name,
|
||||
value: avatar.avatar_id,
|
||||
})),
|
||||
...characters.talking_photos.map((photo) => ({
|
||||
label: photo.talking_photo_name,
|
||||
value: photo.talking_photo_id,
|
||||
})),
|
||||
];
|
||||
|
||||
fields[fieldKey] = Property.StaticDropdown({
|
||||
displayName: fieldKey,
|
||||
required: false,
|
||||
description: 'Select one of avatar or talking photo.',
|
||||
options: { disabled: false, options },
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'voice': {
|
||||
const voices = await heygenApiCall<{
|
||||
voices: { name: string; voice_id: string }[];
|
||||
}>({
|
||||
apiKey: auth as unknown as string,
|
||||
method: HttpMethod.GET,
|
||||
resourceUri: `/voices`,
|
||||
apiVersion: 'v2',
|
||||
});
|
||||
|
||||
fields[fieldKey] = Property.StaticDropdown({
|
||||
displayName: fieldKey,
|
||||
required: false,
|
||||
options: {
|
||||
disabled: false,
|
||||
options: voices.voices.map((voice) => ({
|
||||
label: voice.name,
|
||||
value: voice.voice_id,
|
||||
})),
|
||||
},
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
} catch (error) {
|
||||
console.error(`${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
return {};
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { heygenApiCall } from '../common/client';
|
||||
import { heygenAuth } from '../common/auth';
|
||||
|
||||
const TRIGGER_KEY = 'video_generation_completed_trigger';
|
||||
|
||||
export const videoGenerationCompletedTrigger = createTrigger({
|
||||
auth: heygenAuth,
|
||||
name: 'video_generation_completed',
|
||||
displayName: 'New Avatar Video Event (Success)',
|
||||
description: 'Triggers when a video is generated successfully.',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {},
|
||||
sampleData: {
|
||||
event_type: 'avatar_video.success',
|
||||
event_data: {
|
||||
video_id: '123',
|
||||
url: 'https://www.example.com',
|
||||
gif_download_url: '<gif_url>',
|
||||
folder_id: '123',
|
||||
callback_id: '123',
|
||||
},
|
||||
},
|
||||
|
||||
async onEnable(context) {
|
||||
const webhook = (await heygenApiCall({
|
||||
apiKey: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/webhook/endpoint.add',
|
||||
apiVersion: 'v1',
|
||||
body: {
|
||||
url: context.webhookUrl,
|
||||
events: ['avatar_video.success'],
|
||||
},
|
||||
})) as { data: { endpoint_id: string } };
|
||||
|
||||
await context.store.put<string>(TRIGGER_KEY, webhook.data.endpoint_id);
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
const webhookId = await context.store.get<string>(TRIGGER_KEY);
|
||||
|
||||
if (webhookId) {
|
||||
await heygenApiCall({
|
||||
apiKey: context.auth.secret_text,
|
||||
method: HttpMethod.DELETE,
|
||||
resourceUri: '/webhook/endpoint.delete',
|
||||
apiVersion: 'v1',
|
||||
query: {
|
||||
endpoint_id: webhookId,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const payload = context.payload.body as {
|
||||
event_type: string;
|
||||
event_data: Record<string, any>;
|
||||
};
|
||||
|
||||
if (payload.event_type !== 'avatar_video.success') return [];
|
||||
|
||||
return [payload.event_data];
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { heygenApiCall } from '../common/client';
|
||||
import { heygenAuth } from '../common/auth';
|
||||
|
||||
const TRIGGER_KEY = 'video_generation_failed_trigger';
|
||||
|
||||
export const videoGenerationFailedTrigger = createTrigger({
|
||||
auth: heygenAuth,
|
||||
name: 'video_generation_failed',
|
||||
displayName: 'New Avatar Video Event (Fail)',
|
||||
description: 'Triggers when a video generation process fails.',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {},
|
||||
|
||||
sampleData: {
|
||||
event_type: 'avatar_video.fail',
|
||||
event_data: {
|
||||
video_id: 'abc',
|
||||
msg: 'Failed',
|
||||
callback_id: '123',
|
||||
},
|
||||
},
|
||||
|
||||
async onEnable(context) {
|
||||
const webhook = (await heygenApiCall({
|
||||
apiKey: context.auth.secret_text,
|
||||
method: HttpMethod.POST,
|
||||
resourceUri: '/webhook/endpoint.add',
|
||||
apiVersion: 'v1',
|
||||
body: {
|
||||
url: context.webhookUrl,
|
||||
events: ['avatar_video.fail'],
|
||||
},
|
||||
})) as { data: { endpoint_id: string } };
|
||||
|
||||
await context.store.put<string>(TRIGGER_KEY, webhook.data.endpoint_id);
|
||||
},
|
||||
|
||||
async onDisable(context) {
|
||||
const webhookId = await context.store.get<string>(TRIGGER_KEY);
|
||||
|
||||
if (webhookId) {
|
||||
await heygenApiCall({
|
||||
apiKey: context.auth.secret_text,
|
||||
method: HttpMethod.DELETE,
|
||||
resourceUri: '/webhook/endpoint.delete',
|
||||
apiVersion: 'v1',
|
||||
query: {
|
||||
endpoint_id: webhookId,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
async run(context) {
|
||||
const payload = context.payload.body as {
|
||||
event_type: string;
|
||||
event_data: Record<string, any>;
|
||||
};
|
||||
|
||||
if (payload.event_type !== 'avatar_video.fail') return [];
|
||||
|
||||
return [payload];
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user