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:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,33 @@
{
"extends": [
"../../../../.eslintrc.base.json"
],
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}

View File

@@ -0,0 +1,7 @@
# pieces-gladia
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-gladia` to build the library.

View File

@@ -0,0 +1,10 @@
{
"name": "@activepieces/piece-gladia",
"version": "0.0.1",
"type": "commonjs",
"main": "./src/index.js",
"types": "./src/index.d.ts",
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,65 @@
{
"name": "pieces-gladia",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/gladia/src",
"projectType": "library",
"release": {
"version": {
"manifestRootsToUpdate": [
"dist/{projectRoot}"
],
"currentVersionResolver": "git-tag",
"fallbackCurrentVersionResolver": "disk"
}
},
"tags": [],
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "dist/packages/pieces/community/gladia",
"tsConfig": "packages/pieces/community/gladia/tsconfig.lib.json",
"packageJson": "packages/pieces/community/gladia/package.json",
"main": "packages/pieces/community/gladia/src/index.ts",
"assets": [
"packages/pieces/community/gladia/*.md",
{
"input": "packages/pieces/community/gladia/src/i18n",
"output": "./src/i18n",
"glob": "**/!(i18n.json)"
}
],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true
},
"dependsOn": [
"prebuild",
"^build"
]
},
"nx-release-publish": {
"options": {
"packageRoot": "dist/{projectRoot}"
}
},
"prebuild": {
"dependsOn": [
"^build"
],
"executor": "nx:run-commands",
"options": {
"cwd": "packages/pieces/community/gladia",
"command": "bun install --no-save --silent"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": [
"{options.outputFile}"
]
}
}
}

View File

@@ -0,0 +1,150 @@
{
"\n Enter your Gladia API Key. You can find it in your Gladia account (https://app.gladia.io/apikeys).\n": "\n Enter your Gladia API Key. You can find it in your Gladia account (https://app.gladia.io/apikeys).\n",
"Create Transcription": "Create Transcription",
"Upload Audio File": "Upload Audio File",
"Custom API Call": "Custom API Call",
"Initiate a pre-recorded transcription job from an audio or video URL": "Initiate a pre-recorded transcription job from an audio or video URL",
"Upload an audio or video file for use in a pre-recorded transcription job": "Upload an audio or video file for use in a pre-recorded transcription job",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Audio URL": "Audio URL",
"Language": "Language",
"Enable Code Switching": "Enable Code Switching",
"Enable Subtitles": "Enable Subtitles",
"Subtitles Format": "Subtitles Format",
"Enable Diarization": "Enable Diarization",
"Enable Translation": "Enable Translation",
"Enable Summarization": "Enable Summarization",
"Summarization Type": "Summarization Type",
"Enable Sentiment Analysis": "Enable Sentiment Analysis",
"Enable Sentences": "Enable Sentences",
"Custom Metadata": "Custom Metadata",
"Audio File": "Audio File",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"URL to a Gladia file or to an external audio or video file": "URL to a Gladia file or to an external audio or video file",
"Select the language spoken in the audio for better transcription accuracy": "Select the language spoken in the audio for better transcription accuracy",
"Enable code switching to handle multiple languages in the audio": "Enable code switching to handle multiple languages in the audio",
"Enable subtitles generation for this transcription": "Enable subtitles generation for this transcription",
"Select the subtitle format(s) for transcription output": "Select the subtitle format(s) for transcription output",
"Enable speaker recognition (diarization) for this audio": "Enable speaker recognition (diarization) for this audio",
"Enable translation for this audio": "Enable translation for this audio",
"Enable summarization for this audio": "Enable summarization for this audio",
"Choose the type of summarization to apply. ": "Choose the type of summarization to apply. ",
"Enable sentiment analysis for this audio": "Enable sentiment analysis for this audio",
"Enable sentence detection for this audio": "Enable sentence detection for this audio",
"Add custom metadata to the transcription job": "Add custom metadata to the transcription job",
"The audio or video file to upload": "The audio or video file to upload",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"Auto Detect": "Auto Detect",
"Afrikaans": "Afrikaans",
"Amharic": "Amharic",
"Arabic": "Arabic",
"Assamese": "Assamese",
"Azerbaijani": "Azerbaijani",
"Bashkir": "Bashkir",
"Belarusian": "Belarusian",
"Bulgarian": "Bulgarian",
"Bengali": "Bengali",
"Tibetan": "Tibetan",
"Breton": "Breton",
"Bosnian": "Bosnian",
"Catalan": "Catalan",
"Czech": "Czech",
"Welsh": "Welsh",
"Danish": "Danish",
"German": "German",
"Greek": "Greek",
"English": "English",
"Spanish": "Spanish",
"Estonian": "Estonian",
"Basque": "Basque",
"Persian": "Persian",
"Finnish": "Finnish",
"Faroese": "Faroese",
"French": "French",
"Galician": "Galician",
"Gujarati": "Gujarati",
"Hausa": "Hausa",
"Hawaiian": "Hawaiian",
"Hebrew": "Hebrew",
"Hindi": "Hindi",
"Croatian": "Croatian",
"Haitian Creole": "Haitian Creole",
"Hungarian": "Hungarian",
"Armenian": "Armenian",
"Indonesian": "Indonesian",
"Icelandic": "Icelandic",
"Italian": "Italian",
"Japanese": "Japanese",
"Javanese": "Javanese",
"Georgian": "Georgian",
"Kazakh": "Kazakh",
"Khmer": "Khmer",
"Kannada": "Kannada",
"Korean": "Korean",
"Latin": "Latin",
"Luxembourgish": "Luxembourgish",
"Lingala": "Lingala",
"Lao": "Lao",
"Lithuanian": "Lithuanian",
"Latvian": "Latvian",
"Malagasy": "Malagasy",
"Maori": "Maori",
"Macedonian": "Macedonian",
"Malayalam": "Malayalam",
"Mongolian": "Mongolian",
"Marathi": "Marathi",
"Malay": "Malay",
"Maltese": "Maltese",
"Burmese": "Burmese",
"Nepali": "Nepali",
"Dutch": "Dutch",
"Norwegian Nynorsk": "Norwegian Nynorsk",
"Norwegian": "Norwegian",
"Occitan": "Occitan",
"Punjabi": "Punjabi",
"Polish": "Polish",
"Pashto": "Pashto",
"Portuguese": "Portuguese",
"Romanian": "Romanian",
"Russian": "Russian",
"Sanskrit": "Sanskrit",
"Sindhi": "Sindhi",
"Sinhala": "Sinhala",
"Slovak": "Slovak",
"Slovenian": "Slovenian",
"Shona": "Shona",
"Somali": "Somali",
"Albanian": "Albanian",
"Serbian": "Serbian",
"Sundanese": "Sundanese",
"Swedish": "Swedish",
"Swahili": "Swahili",
"Tamil": "Tamil",
"Telugu": "Telugu",
"Tajik": "Tajik",
"Thai": "Thai",
"Turkmen": "Turkmen",
"Tagalog": "Tagalog",
"Turkish": "Turkish",
"Tatar": "Tatar",
"Ukrainian": "Ukrainian",
"Urdu": "Urdu",
"Uzbek": "Uzbek",
"Vietnamese": "Vietnamese",
"Yiddish": "Yiddish",
"Yoruba": "Yoruba",
"Chinese": "Chinese",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD"
}

View File

@@ -0,0 +1,27 @@
import { createPiece } from '@activepieces/pieces-framework';
import { PieceCategory } from '@activepieces/shared';
import { createTranscription } from './lib/actions/create-transcription';
import { uploadAFile } from './lib/actions/upload-a-file';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
import { gladiaAuth } from './lib/common/auth';
export const gladia = createPiece({
displayName: 'Gladia',
auth: gladiaAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/gladia.png',
categories: [PieceCategory.ARTIFICIAL_INTELLIGENCE],
authors: ['sanket-a11y'],
actions: [
createTranscription,
uploadAFile,
createCustomApiCallAction({
baseUrl: () => `https://api.gladia.io/v2`,
auth: gladiaAuth,
authMapping: async (auth) => ({
'x-gladia-key': auth.secret_text,
}),
}),
],
triggers: [],
});

View File

@@ -0,0 +1,190 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
import { gladiaAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { languageDropdownOptions } from '../common/props';
export const createTranscription = createAction({
auth: gladiaAuth,
name: 'createTranscription',
displayName: 'Create Transcription',
description:
'Initiate a pre-recorded transcription job from an audio or video URL',
props: {
audio_url: Property.LongText({
displayName: 'Audio URL',
description: 'URL to a Gladia file or to an external audio or video file',
required: true,
}),
languages: Property.StaticDropdown({
displayName: 'Language',
description:
'Select the language spoken in the audio for better transcription accuracy',
required: false,
options: {
options: languageDropdownOptions,
},
}),
code_switching: Property.Checkbox({
displayName: 'Enable Code Switching',
description:
'Enable code switching to handle multiple languages in the audio',
required: false,
defaultValue: false,
}),
subtitles: Property.Checkbox({
displayName: 'Enable Subtitles',
description: 'Enable subtitles generation for this transcription',
required: false,
defaultValue: false,
}),
subtitles_format: Property.Dropdown({
displayName: 'Subtitles Format',
description: 'Select the subtitle format(s) for transcription output',
required: false,
auth: gladiaAuth,
refreshers: ['subtitles'],
options: async ({ subtitles }) => {
if (!subtitles) {
return {
disabled: true,
options: [],
placeholder: 'Enable subtitles to select type',
};
}
return {
disabled: false,
options: [
{ label: 'SRT', value: 'srt' },
{ label: 'VTT', value: 'vtt' },
],
};
},
}),
diarization: Property.Checkbox({
displayName: 'Enable Diarization',
description: 'Enable speaker recognition (diarization) for this audio',
required: false,
defaultValue: false,
}),
translation: Property.Checkbox({
displayName: 'Enable Translation',
description: 'Enable translation for this audio',
required: false,
defaultValue: false,
}),
summarization: Property.Checkbox({
displayName: 'Enable Summarization',
description: 'Enable summarization for this audio',
required: false,
defaultValue: false,
}),
summarization_type: Property.Dropdown({
displayName: 'Summarization Type',
description: 'Choose the type of summarization to apply. ',
required: false,
auth: gladiaAuth,
refreshers: ['summarization'],
options: async ({ summarization }) => {
if (!summarization) {
return {
disabled: true,
options: [],
placeholder: 'Enable summarization to select type',
};
}
return {
disabled: false,
options: [
{ label: 'General', value: 'general' },
{ label: 'Bullet Points', value: 'bullet_points' },
{ label: 'Concise', value: 'concise' },
],
};
},
}),
sentiment_analysis: Property.Checkbox({
displayName: 'Enable Sentiment Analysis',
description: 'Enable sentiment analysis for this audio',
required: false,
defaultValue: false,
}),
sentences: Property.Checkbox({
displayName: 'Enable Sentences',
description: 'Enable sentence detection for this audio',
required: false,
defaultValue: false,
}),
custom_metadata: Property.Object({
displayName: 'Custom Metadata',
description: 'Add custom metadata to the transcription job',
required: false,
}),
},
async run(context) {
const apiKey = context.auth.secret_text;
const {
audio_url,
languages,
code_switching,
subtitles,
subtitles_format,
diarization,
translation,
summarization,
summarization_type,
sentiment_analysis,
sentences,
custom_metadata,
} = context.propsValue;
const body: Record<string, unknown> = {
audio_url,
sentences,
};
if (languages) {
body['language_config'] = { language: languages, code_switching };
}
if (subtitles) {
body['subtitles'] = subtitles;
if (subtitles_format && subtitles_format.length > 0) {
body['subtitles_config'] = { formats: subtitles_format };
}
}
if (diarization) {
body['diarization'] = diarization;
}
if (translation) {
body['translation'] = translation;
}
if (summarization) {
body['summarization'] = summarization;
if (summarization_type) {
body['summarization_config'] = { type: summarization_type };
}
}
if (sentiment_analysis) {
body['sentiment_analysis'] = sentiment_analysis;
}
if (custom_metadata) {
body['custom_metadata'] = custom_metadata;
}
const response = await makeRequest(
apiKey,
HttpMethod.POST,
'/pre-recorded',
body
);
const transcription = await makeRequest(
apiKey,
HttpMethod.GET,
`/pre-recorded/${response.id}`
);
return transcription;
},
});

View File

@@ -0,0 +1,53 @@
import {
createAction,
Property,
ActionContext,
} from '@activepieces/pieces-framework';
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { gladiaAuth } from '../common/auth';
import { BASE_URL } from '../common/client';
import FormData from 'form-data';
export const uploadAFile = createAction({
auth: gladiaAuth,
name: 'uploadAFile',
displayName: 'Upload Audio File',
description:
'Upload an audio or video file for use in a pre-recorded transcription job',
props: {
audio_file: Property.File({
displayName: 'Audio File',
description: 'The audio or video file to upload',
required: true,
}),
},
async run(context: ActionContext<typeof gladiaAuth>) {
const apiKey = context.auth.secret_text;
const audioFile = context.propsValue['audio_file'];
if (!audioFile) {
throw new Error('Audio file is required');
}
const formData = new FormData();
formData.append('audio', Buffer.from(audioFile.data), audioFile.filename);
try {
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${BASE_URL}/upload`,
headers: {
'x-gladia-key': apiKey,
...formData.getHeaders(),
},
body: formData,
});
return response.body;
} catch (error: Error | unknown) {
const errorMessage =
error instanceof Error ? error.message : String(error);
throw new Error(`Failed to upload file: ${errorMessage}`);
}
},
});

View File

@@ -0,0 +1,30 @@
import { PieceAuth } from '@activepieces/pieces-framework';
import { makeRequest } from './client';
import { HttpMethod } from '@activepieces/pieces-common';
export const gladiaAuth = PieceAuth.SecretText({
displayName: 'Gladia API Key',
description: `
Enter your Gladia API Key. You can find it in your Gladia account (https://app.gladia.io/apikeys).
`,
required: true,
validate: async ({ auth }) => {
if (auth) {
try {
await makeRequest(auth as string, HttpMethod.GET, '/transcription');
return {
valid: true,
};
} catch (error) {
return {
valid: false,
error: 'Invalid Api Key',
};
}
}
return {
valid: false,
error: 'Invalid Api Key',
};
},
});

View File

@@ -0,0 +1,25 @@
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
export const BASE_URL = `https://api.gladia.io/v2`;
export async function makeRequest(
api_key: string,
method: HttpMethod,
path: string,
body?: unknown
) {
try {
const response = await httpClient.sendRequest({
method,
url: `${BASE_URL}${path}`,
headers: {
'x-gladia-key': `${api_key}`,
'Content-Type': 'application/json',
},
body,
});
return response.body;
} catch (error: any) {
throw new Error(`Unexpected error: ${error.message || String(error)}`);
}
}

View File

@@ -0,0 +1,102 @@
export const languageDropdownOptions = [
{ label: 'Auto Detect', value: 'auto' },
{ label: 'Afrikaans', value: 'af' },
{ label: 'Amharic', value: 'am' },
{ label: 'Arabic', value: 'ar' },
{ label: 'Assamese', value: 'as' },
{ label: 'Azerbaijani', value: 'az' },
{ label: 'Bashkir', value: 'ba' },
{ label: 'Belarusian', value: 'be' },
{ label: 'Bulgarian', value: 'bg' },
{ label: 'Bengali', value: 'bn' },
{ label: 'Tibetan', value: 'bo' },
{ label: 'Breton', value: 'br' },
{ label: 'Bosnian', value: 'bs' },
{ label: 'Catalan', value: 'ca' },
{ label: 'Czech', value: 'cs' },
{ label: 'Welsh', value: 'cy' },
{ label: 'Danish', value: 'da' },
{ label: 'German', value: 'de' },
{ label: 'Greek', value: 'el' },
{ label: 'English', value: 'en' },
{ label: 'Spanish', value: 'es' },
{ label: 'Estonian', value: 'et' },
{ label: 'Basque', value: 'eu' },
{ label: 'Persian', value: 'fa' },
{ label: 'Finnish', value: 'fi' },
{ label: 'Faroese', value: 'fo' },
{ label: 'French', value: 'fr' },
{ label: 'Galician', value: 'gl' },
{ label: 'Gujarati', value: 'gu' },
{ label: 'Hausa', value: 'ha' },
{ label: 'Hawaiian', value: 'haw' },
{ label: 'Hebrew', value: 'he' },
{ label: 'Hindi', value: 'hi' },
{ label: 'Croatian', value: 'hr' },
{ label: 'Haitian Creole', value: 'ht' },
{ label: 'Hungarian', value: 'hu' },
{ label: 'Armenian', value: 'hy' },
{ label: 'Indonesian', value: 'id' },
{ label: 'Icelandic', value: 'is' },
{ label: 'Italian', value: 'it' },
{ label: 'Japanese', value: 'ja' },
{ label: 'Javanese', value: 'jw' },
{ label: 'Georgian', value: 'ka' },
{ label: 'Kazakh', value: 'kk' },
{ label: 'Khmer', value: 'km' },
{ label: 'Kannada', value: 'kn' },
{ label: 'Korean', value: 'ko' },
{ label: 'Latin', value: 'la' },
{ label: 'Luxembourgish', value: 'lb' },
{ label: 'Lingala', value: 'ln' },
{ label: 'Lao', value: 'lo' },
{ label: 'Lithuanian', value: 'lt' },
{ label: 'Latvian', value: 'lv' },
{ label: 'Malagasy', value: 'mg' },
{ label: 'Maori', value: 'mi' },
{ label: 'Macedonian', value: 'mk' },
{ label: 'Malayalam', value: 'ml' },
{ label: 'Mongolian', value: 'mn' },
{ label: 'Marathi', value: 'mr' },
{ label: 'Malay', value: 'ms' },
{ label: 'Maltese', value: 'mt' },
{ label: 'Burmese', value: 'my' },
{ label: 'Nepali', value: 'ne' },
{ label: 'Dutch', value: 'nl' },
{ label: 'Norwegian Nynorsk', value: 'nn' },
{ label: 'Norwegian', value: 'no' },
{ label: 'Occitan', value: 'oc' },
{ label: 'Punjabi', value: 'pa' },
{ label: 'Polish', value: 'pl' },
{ label: 'Pashto', value: 'ps' },
{ label: 'Portuguese', value: 'pt' },
{ label: 'Romanian', value: 'ro' },
{ label: 'Russian', value: 'ru' },
{ label: 'Sanskrit', value: 'sa' },
{ label: 'Sindhi', value: 'sd' },
{ label: 'Sinhala', value: 'si' },
{ label: 'Slovak', value: 'sk' },
{ label: 'Slovenian', value: 'sl' },
{ label: 'Shona', value: 'sn' },
{ label: 'Somali', value: 'so' },
{ label: 'Albanian', value: 'sq' },
{ label: 'Serbian', value: 'sr' },
{ label: 'Sundanese', value: 'su' },
{ label: 'Swedish', value: 'sv' },
{ label: 'Swahili', value: 'sw' },
{ label: 'Tamil', value: 'ta' },
{ label: 'Telugu', value: 'te' },
{ label: 'Tajik', value: 'tg' },
{ label: 'Thai', value: 'th' },
{ label: 'Turkmen', value: 'tk' },
{ label: 'Tagalog', value: 'tl' },
{ label: 'Turkish', value: 'tr' },
{ label: 'Tatar', value: 'tt' },
{ label: 'Ukrainian', value: 'uk' },
{ label: 'Urdu', value: 'ur' },
{ label: 'Uzbek', value: 'uz' },
{ label: 'Vietnamese', value: 'vi' },
{ label: 'Yiddish', value: 'yi' },
{ label: 'Yoruba', value: 'yo' },
{ label: 'Chinese', value: 'zh' },
];

View File

@@ -0,0 +1,20 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
"importHelpers": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noPropertyAccessFromIndexSignature": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"include": ["src/**/*.ts"]
}