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,86 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { easyPeasyAiAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const customGeneratorText = createAction({
auth: easyPeasyAiAuth,
name: 'customGeneratorText',
displayName: 'Custom Generator (Text)',
description:
'Generate custom text for any purpose using the EasyPeasy AI template engine',
props: {
keywords: Property.LongText({
displayName: 'Keywords',
description: 'What do you want to generate? (max 1000 characters)',
required: true,
}),
extra1: Property.LongText({
displayName: 'Background Information',
description:
'Additional context or background information (optional, max 1000 characters)',
required: false,
}),
outputs: Property.Number({
displayName: 'Number of Outputs',
description: 'How many outputs to generate (default: 1)',
required: false,
defaultValue: 1,
}),
language: Property.StaticDropdown({
displayName: 'Language',
description: 'Language for the generated text (default: English)',
required: false,
options: {
disabled: false,
options: [
{ label: 'English', value: 'English' },
{ label: 'Spanish', value: 'Spanish' },
{ label: 'French', value: 'French' },
{ label: 'German', value: 'German' },
{ label: 'Italian', value: 'Italian' },
{ label: 'Portuguese', value: 'Portuguese' },
{ label: 'Dutch', value: 'Dutch' },
{ label: 'Russian', value: 'Russian' },
{ label: 'Chinese', value: 'Chinese' },
{ label: 'Japanese', value: 'Japanese' },
{ label: 'Korean', value: 'Korean' },
{ label: 'Hindi', value: 'Hindi' },
{ label: 'Arabic', value: 'Arabic' },
],
},
defaultValue: 'English',
}),
shouldUseGPT4: Property.Checkbox({
displayName: 'Use GPT-4',
description: 'Use GPT-4 model for generation (may incur higher costs)',
required: false,
defaultValue: false,
}),
},
async run(context) {
const { keywords, extra1, outputs, language, shouldUseGPT4 } =
context.propsValue;
const payload = {
preset: 'custom-generator',
keywords,
outputs: outputs || 1,
language: language || 'English',
shouldUseGPT4: shouldUseGPT4 || false,
};
if (extra1) {
Object.assign(payload, { extra1 });
}
const response = await makeRequest(
context.auth.secret_text,
HttpMethod.POST,
'/api/generate',
payload
);
return response;
},
});

View File

@@ -0,0 +1,105 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { easyPeasyAiAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const generateAiImage = createAction({
auth: easyPeasyAiAuth,
name: 'generateAiImage',
displayName: 'Generate AI Image',
description:
'Generate AI images based on text prompts using various models and styles',
props: {
prompt: Property.LongText({
displayName: 'Prompt',
description: 'Description of the image you want to generate',
required: true,
}),
model: Property.StaticDropdown({
displayName: 'Model',
description: 'AI model to use for image generation',
required: true,
options: {
disabled: false,
options: [
{ label: 'DALL-E 3', value: 'DALL-E 3' },
{ label: 'DALL-E 2', value: 'DALL-E 2' },
{ label: 'Midjourney', value: 'Midjourney' },
{ label: 'Stable Diffusion', value: 'Stable Diffusion' },
],
},
}),
style: Property.ShortText({
displayName: 'Style',
description:
'Art style or aesthetic for the generated image (e.g., "oil painting", "watercolor", "cyberpunk")',
required: false,
}),
artist: Property.ShortText({
displayName: 'Artist Inspiration',
description:
'Art style inspired by a specific artist (e.g., "Van Gogh", "Picasso")',
required: false,
}),
dimensions: Property.StaticDropdown({
displayName: 'Dimensions',
description: 'Image dimensions/aspect ratio',
required: false,
options: {
disabled: false,
options: [
{ label: '1024x1024', value: '1024x1024' },
{ label: '1024x1792', value: '1024x1792' },
{ label: '1792x1024', value: '1792x1024' },
{ label: '512x512', value: '512x512' },
{ label: '256x256', value: '256x256' },
],
},
defaultValue: '1024x1024',
}),
useHD: Property.Checkbox({
displayName: 'Use HD Quality',
description: 'Generate image in HD quality (may incur higher costs)',
required: false,
defaultValue: true,
}),
image: Property.ShortText({
displayName: 'Image Reference URL',
description: 'Optional URL to a reference image for style consistency',
required: false,
}),
},
async run(context) {
const { prompt, model, style, artist, dimensions, useHD, image } =
context.propsValue;
const payload: any = {
prompt,
model,
useHD: useHD || true,
};
// Add optional fields if provided
if (style) {
payload.style = style;
}
if (artist) {
payload.artist = artist;
}
if (dimensions) {
payload.dimensions = dimensions;
}
if (image) {
payload.image = image;
}
const response = await makeRequest(
context.auth.secret_text,
HttpMethod.POST,
'/api/generate-image',
payload
);
return response;
},
});

View File

@@ -0,0 +1,106 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { easyPeasyAiAuth } from '../common/auth';
import { HttpMethod } from '@activepieces/pieces-common';
import { makeRequest } from '../common/client';
export const getAiTranscription = createAction({
auth: easyPeasyAiAuth,
name: 'getAiTranscription',
displayName: 'Get AI Transcription',
description:
'Generate AI transcriptions from audio files with speaker detection and enhanced quality options',
props: {
url: Property.ShortText({
displayName: 'Audio File URL',
description: 'URL to the audio file to transcribe',
required: true,
}),
name: Property.ShortText({
displayName: 'Transcription Name',
description: 'Name or title for this transcription',
required: true,
}),
audio_type: Property.StaticDropdown({
displayName: 'Audio Type',
description: 'Type of audio content being transcribed',
required: true,
options: {
disabled: false,
options: [
{ label: 'Podcast', value: 'podcast' },
{ label: 'Interview', value: 'interview' },
{ label: 'Meeting', value: 'meeting' },
{ label: 'Lecture', value: 'lecture' },
{ label: 'Presentation', value: 'presentation' },
{ label: 'Other', value: 'other' },
],
},
}),
language: Property.StaticDropdown({
displayName: 'Language',
description: 'Language of the audio content',
required: false,
options: {
disabled: false,
options: [
{ label: 'English', value: 'English' },
{ label: 'Spanish', value: 'Spanish' },
{ label: 'French', value: 'French' },
{ label: 'German', value: 'German' },
{ label: 'Italian', value: 'Italian' },
{ label: 'Portuguese', value: 'Portuguese' },
{ label: 'Dutch', value: 'Dutch' },
{ label: 'Russian', value: 'Russian' },
{ label: 'Chinese', value: 'Chinese' },
{ label: 'Japanese', value: 'Japanese' },
{ label: 'Korean', value: 'Korean' },
{ label: 'Hindi', value: 'Hindi' },
{ label: 'Arabic', value: 'Arabic' },
],
},
defaultValue: 'English',
}),
detect_speakers: Property.Checkbox({
displayName: 'Detect Speakers',
description:
'Automatically detect and identify different speakers in the audio',
required: false,
defaultValue: true,
}),
enhanced_quality: Property.Checkbox({
displayName: 'Enhanced Quality',
description:
'Use enhanced quality processing for better transcription accuracy',
required: false,
defaultValue: true,
}),
},
async run(context) {
const {
url,
name,
audio_type,
language,
detect_speakers,
enhanced_quality,
} = context.propsValue;
const payload = {
url,
name,
audio_type,
language: language || 'English',
detect_speakers: detect_speakers || true,
enhanced_quality: enhanced_quality || true,
};
const response = await makeRequest(
context.auth.secret_text,
HttpMethod.POST,
'/api/transcriptions',
payload
);
return response;
},
});

View File

@@ -0,0 +1,8 @@
import { PieceAuth } from '@activepieces/pieces-framework';
export const easyPeasyAiAuth = PieceAuth.SecretText({
displayName: 'API Key',
description:
'Easy Peasy AI API Key. Get it from [Easy Peasy AI Settings](https://easy-peasy.ai/settings) - Navigate to the **API** tab from the top bar',
required: true,
});

View File

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