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,121 @@
|
||||
{
|
||||
"Writesonic-bulk AI-powered writing assistant": "Writesonic-bulk AI-powered writing assistant",
|
||||
"\nTo get your API Key:\n\n1. Go to [app.writesonic.com](https://app.writesonic.com/)\n2. Login to your Writesonic account\n3. Hover over your display picture on the top-right corner to open the profile menu\n4. Click on \"API Dashboard\"\n5. Click on the switch to activate the API\n6. Click on \"Reveal API Key\"\n7. Copy and save your API key securely (never commit to public repositories)\n": "\nTo get your API Key:\n\n1. Go to [app.writesonic.com](https://app.writesonic.com/)\n2. Login to your Writesonic account\n3. Hover over your display picture on the top-right corner to open the profile menu\n4. Click on \"API Dashboard\"\n5. Click on the switch to activate the API\n6. Click on \"Reveal API Key\"\n7. Copy and save your API key securely (never commit to public repositories)\n",
|
||||
"Blog Ideas": "Blog Ideas",
|
||||
"Blog Intros": "Blog Intros",
|
||||
"Blog Outlines": "Blog Outlines",
|
||||
"Content Rephraser": "Content Rephraser",
|
||||
"Content Shorten": "Content Shorten",
|
||||
"Facebook Ads": "Facebook Ads",
|
||||
"Generate Product Descriptions": "Generate Product Descriptions",
|
||||
"Google Ads": "Google Ads",
|
||||
"Landing Page Headlines": "Landing Page Headlines",
|
||||
"Sentence Expander": "Sentence Expander",
|
||||
"Custom API Call": "Custom API Call",
|
||||
"Generate blog article ideas based on a topic or keyword": "Generate blog article ideas based on a topic or keyword",
|
||||
"Generate enticing blog article introductions": "Generate enticing blog article introductions",
|
||||
"Generate detailed article outlines for better content writing": "Generate detailed article outlines for better content writing",
|
||||
"Rephrase content in a different voice and style to appeal to different readers": "Rephrase content in a different voice and style to appeal to different readers",
|
||||
"Shorten your content in a different voice and style to appeal to different readers": "Shorten your content in a different voice and style to appeal to different readers",
|
||||
"Generate Facebook ad copies that make your ads truly stand out": "Generate Facebook ad copies that make your ads truly stand out",
|
||||
"Generate authentic product descriptions that compel, inspire, and influence": "Generate authentic product descriptions that compel, inspire, and influence",
|
||||
"Generate quality ads that rank in search results and drive more traffic": "Generate quality ads that rank in search results and drive more traffic",
|
||||
"Generate unique and catchy headlines perfect for your product or service": "Generate unique and catchy headlines perfect for your product or service",
|
||||
"Expand short sentences into more descriptive and interesting ones": "Expand short sentences into more descriptive and interesting ones",
|
||||
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
|
||||
"Topic": "Topic",
|
||||
"Keyword": "Keyword",
|
||||
"Engine": "Engine",
|
||||
"Language": "Language",
|
||||
"Number of Copies": "Number of Copies",
|
||||
"Blog title": "Blog title",
|
||||
"Blog Title": "Blog Title",
|
||||
"Blog Introduction": "Blog Introduction",
|
||||
"Original Content": "Original Content",
|
||||
"Tone of Voice": "Tone of Voice",
|
||||
"Product Name": "Product Name",
|
||||
"Product Description": "Product Description",
|
||||
"Occasion": "Occasion",
|
||||
"Promotion": "Promotion",
|
||||
"Product Characteristics": "Product Characteristics",
|
||||
"Primary Keyword": "Primary Keyword",
|
||||
"Secondary Keywords": "Secondary Keywords",
|
||||
"Search Term": "Search Term",
|
||||
"Sentence": "Sentence",
|
||||
"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)",
|
||||
"The topic or keyword to generate blog ideas for": "The topic or keyword to generate blog ideas for",
|
||||
"A keyword to include in the blog introduction": "A keyword to include in the blog introduction",
|
||||
"Select the engine quality level": "Select the engine quality level",
|
||||
"Select the language": "Select the language",
|
||||
"Number of blog ideas to generate (1-5)": "Number of blog ideas to generate (1-5)",
|
||||
"The blog topic or title to generate an introduction for": "The blog topic or title to generate an introduction for",
|
||||
"The blog topic or title to generate an outline for": "The blog topic or title to generate an outline for",
|
||||
"The introduction of the blog to base the outline on": "The introduction of the blog to base the outline on",
|
||||
"The content you want to rephrase": "The content you want to rephrase",
|
||||
"Select the tone of voice for the content": "Select the tone of voice for the content",
|
||||
"The content you want to shorten": "The content you want to shorten",
|
||||
"The name of the product or service to advertise": "The name of the product or service to advertise",
|
||||
"A brief description of the product or service": "A brief description of the product or service",
|
||||
"The occasion for the ad (e.g.,\"Black Friday\", holiday, sale event)": "The occasion for the ad (e.g.,\"Black Friday\", holiday, sale event)",
|
||||
"Details about any promotion or discount": "Details about any promotion or discount",
|
||||
"The name of the product": "The name of the product",
|
||||
"Key characteristics and specifications of the product": "Key characteristics and specifications of the product",
|
||||
"The main keyword to include in the product description": "The main keyword to include in the product description",
|
||||
"Additional keywords to include in the product description, separated by commas": "Additional keywords to include in the product description, separated by commas",
|
||||
"The search term or query to target in the Google Ads campaign": "The search term or query to target in the Google Ads campaign",
|
||||
"The name of the product or service": "The name of the product or service",
|
||||
"The sentence you want to expand": "The sentence you want to expand",
|
||||
"A keyword to include in the expanded sentence": "A keyword to include in the expanded sentence",
|
||||
"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..",
|
||||
"Economy": "Economy",
|
||||
"Average": "Average",
|
||||
"Good": "Good",
|
||||
"Premium": "Premium",
|
||||
"English": "English",
|
||||
"Dutch": "Dutch",
|
||||
"French": "French",
|
||||
"German": "German",
|
||||
"Italian": "Italian",
|
||||
"Polish": "Polish",
|
||||
"Spanish": "Spanish",
|
||||
"Portuguese (Portugal)": "Portuguese (Portugal)",
|
||||
"Portuguese (Brazil)": "Portuguese (Brazil)",
|
||||
"Russian": "Russian",
|
||||
"Japanese": "Japanese",
|
||||
"Chinese": "Chinese",
|
||||
"Bulgarian": "Bulgarian",
|
||||
"Czech": "Czech",
|
||||
"Danish": "Danish",
|
||||
"Greek": "Greek",
|
||||
"Hungarian": "Hungarian",
|
||||
"Lithuanian": "Lithuanian",
|
||||
"Latvian": "Latvian",
|
||||
"Romanian": "Romanian",
|
||||
"Slovak": "Slovak",
|
||||
"Slovenian": "Slovenian",
|
||||
"Swedish": "Swedish",
|
||||
"Finnish": "Finnish",
|
||||
"Estonian": "Estonian",
|
||||
"Excited": "Excited",
|
||||
"Professional": "Professional",
|
||||
"Funny": "Funny",
|
||||
"Encouraging": "Encouraging",
|
||||
"Dramatic": "Dramatic",
|
||||
"Witty": "Witty",
|
||||
"Sarcastic": "Sarcastic",
|
||||
"Engaging": "Engaging",
|
||||
"Creative": "Creative",
|
||||
"GET": "GET",
|
||||
"POST": "POST",
|
||||
"PATCH": "PATCH",
|
||||
"PUT": "PUT",
|
||||
"DELETE": "DELETE",
|
||||
"HEAD": "HEAD"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { createPiece } from '@activepieces/pieces-framework';
|
||||
import { blogIdeas } from './lib/actions/blog-ideas';
|
||||
import { blogIntros } from './lib/actions/blog-intros';
|
||||
import { blogOutlines } from './lib/actions/blog-outlines';
|
||||
import { contentRephraser } from './lib/actions/content-rephraser';
|
||||
import { contentShorten } from './lib/actions/content-shorten';
|
||||
import { facebookAds } from './lib/actions/facebook-ads';
|
||||
import { generateProductDescriptions } from './lib/actions/generate-product-descriptions';
|
||||
import { googleAds } from './lib/actions/google-ads';
|
||||
import { landingPageHeadlines } from './lib/actions/landing-page-headlines';
|
||||
import { sentenceExpander } from './lib/actions/sentence-expander';
|
||||
import { createCustomApiCallAction } from '@activepieces/pieces-common';
|
||||
|
||||
import { PieceCategory } from '@activepieces/shared';
|
||||
import { writesonicBulkAuth } from './lib/common/auth';
|
||||
import { BASE_URL } from './lib/common/client';
|
||||
|
||||
export const writesonicBulk = createPiece({
|
||||
displayName: 'Writesonic',
|
||||
auth: writesonicBulkAuth,
|
||||
minimumSupportedRelease: '0.36.1',
|
||||
logoUrl: 'https://cdn.activepieces.com/pieces/writesonic-bulk.png',
|
||||
authors: ['sanket-a11y'],
|
||||
categories: [
|
||||
PieceCategory.ARTIFICIAL_INTELLIGENCE,
|
||||
PieceCategory.CONTENT_AND_FILES,
|
||||
],
|
||||
description: 'Writesonic AI-powered writing assistant',
|
||||
actions: [
|
||||
blogIdeas,
|
||||
blogIntros,
|
||||
blogOutlines,
|
||||
contentRephraser,
|
||||
contentShorten,
|
||||
facebookAds,
|
||||
generateProductDescriptions,
|
||||
googleAds,
|
||||
landingPageHeadlines,
|
||||
sentenceExpander,
|
||||
createCustomApiCallAction({
|
||||
auth: writesonicBulkAuth,
|
||||
baseUrl: () => BASE_URL,
|
||||
authMapping: async (auth) => {
|
||||
return {
|
||||
'X-API-KEY': `${auth.secret_text}`,
|
||||
};
|
||||
},
|
||||
}),
|
||||
],
|
||||
triggers: [],
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import {
|
||||
engineDropdownOptions,
|
||||
languageDropdownOptions,
|
||||
} from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const blogIdeas = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'blogIdeas',
|
||||
displayName: 'Blog Ideas',
|
||||
description: 'Generate blog article ideas based on a topic or keyword',
|
||||
props: {
|
||||
topic: Property.ShortText({
|
||||
displayName: 'Topic',
|
||||
description: 'The topic or keyword to generate blog ideas for',
|
||||
required: true,
|
||||
}),
|
||||
keyword: Property.ShortText({
|
||||
displayName: 'Keyword',
|
||||
description: 'A keyword to include in the blog introduction',
|
||||
required: false,
|
||||
}),
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload: any = {
|
||||
topic: context.propsValue.topic,
|
||||
};
|
||||
if (context.propsValue.keyword) {
|
||||
payload.keyword = context.propsValue.keyword;
|
||||
}
|
||||
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/blog-ideas?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import { engineDropdownOptions } from '../common/props';
|
||||
import { languageDropdownOptions } from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const blogIntros = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'blogIntros',
|
||||
displayName: 'Blog Intros',
|
||||
description: 'Generate enticing blog article introductions',
|
||||
props: {
|
||||
blog_title: Property.ShortText({
|
||||
displayName: 'Blog title',
|
||||
description: 'The blog topic or title to generate an introduction for',
|
||||
required: true,
|
||||
}),
|
||||
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload: any = {
|
||||
blog_title: context.propsValue.blog_title,
|
||||
};
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/blog-intros?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import {
|
||||
engineDropdownOptions,
|
||||
languageDropdownOptions,
|
||||
} from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const blogOutlines = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'blogOutlines',
|
||||
displayName: 'Blog Outlines',
|
||||
description: 'Generate detailed article outlines for better content writing',
|
||||
props: {
|
||||
blog_title: Property.ShortText({
|
||||
displayName: 'Blog Title',
|
||||
description: 'The blog topic or title to generate an outline for',
|
||||
required: true,
|
||||
}),
|
||||
blog_intro: Property.LongText({
|
||||
displayName: 'Blog Introduction',
|
||||
description: 'The introduction of the blog to base the outline on',
|
||||
required: true,
|
||||
}),
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload = {
|
||||
blog_title: context.propsValue.blog_title,
|
||||
blog_intro: context.propsValue.blog_intro,
|
||||
};
|
||||
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/blog-outlines?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import {
|
||||
engineDropdownOptions,
|
||||
languageDropdownOptions,
|
||||
toneofvoiceDropdown,
|
||||
} from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const contentRephraser = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'contentRephraser',
|
||||
displayName: 'Content Rephraser',
|
||||
description:
|
||||
'Rephrase content in a different voice and style to appeal to different readers',
|
||||
props: {
|
||||
content_to_rephrase: Property.LongText({
|
||||
displayName: 'Original Content',
|
||||
description: 'The content you want to rephrase',
|
||||
required: true,
|
||||
}),
|
||||
tone_of_voice: toneofvoiceDropdown,
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload: any = {
|
||||
content_to_rephrase: context.propsValue.content_to_rephrase,
|
||||
};
|
||||
if (context.propsValue.tone_of_voice) {
|
||||
payload.tone_of_voice = context.propsValue.tone_of_voice;
|
||||
}
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/content-rephrases?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import {
|
||||
engineDropdownOptions,
|
||||
languageDropdownOptions,
|
||||
} from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const contentShorten = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'contentShorten',
|
||||
displayName: 'Content Shorten',
|
||||
description:
|
||||
'Shorten your content in a different voice and style to appeal to different readers',
|
||||
props: {
|
||||
content_to_shorten: Property.LongText({
|
||||
displayName: 'Original Content',
|
||||
description: 'The content you want to shorten',
|
||||
required: true,
|
||||
}),
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload = {
|
||||
content_to_shorten: context.propsValue.content_to_shorten,
|
||||
};
|
||||
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/content-shorten?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import {
|
||||
engineDropdownOptions,
|
||||
languageDropdownOptions,
|
||||
} from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const facebookAds = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'facebookAds',
|
||||
displayName: 'Facebook Ads',
|
||||
description: 'Generate Facebook ad copies that make your ads truly stand out',
|
||||
props: {
|
||||
product_name: Property.ShortText({
|
||||
displayName: 'Product Name',
|
||||
description: 'The name of the product or service to advertise',
|
||||
required: true,
|
||||
}),
|
||||
product_description: Property.LongText({
|
||||
displayName: 'Product Description',
|
||||
description: 'A brief description of the product or service',
|
||||
required: false,
|
||||
}),
|
||||
occasion: Property.ShortText({
|
||||
displayName: 'Occasion',
|
||||
description:
|
||||
'The occasion for the ad (e.g.,"Black Friday", holiday, sale event)',
|
||||
required: false,
|
||||
}),
|
||||
promotion: Property.ShortText({
|
||||
displayName: 'Promotion',
|
||||
description: 'Details about any promotion or discount',
|
||||
required: false,
|
||||
}),
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload = {
|
||||
product_name: context.propsValue.product_name,
|
||||
product_description: context.propsValue.product_description,
|
||||
occasion: context.propsValue.occasion,
|
||||
promotion: context.propsValue.promotion,
|
||||
};
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/facebook-ads?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import {
|
||||
engineDropdownOptions,
|
||||
languageDropdownOptions,
|
||||
toneofvoiceDropdown,
|
||||
} from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const generateProductDescriptions = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'generateProductDescriptions',
|
||||
displayName: 'Generate Product Descriptions',
|
||||
description:
|
||||
'Generate authentic product descriptions that compel, inspire, and influence',
|
||||
props: {
|
||||
product_name: Property.ShortText({
|
||||
displayName: 'Product Name',
|
||||
description: 'The name of the product',
|
||||
required: true,
|
||||
}),
|
||||
product_characteristics: Property.LongText({
|
||||
displayName: 'Product Characteristics',
|
||||
description: 'Key characteristics and specifications of the product',
|
||||
required: true,
|
||||
}),
|
||||
primary_keyword: Property.ShortText({
|
||||
displayName: 'Primary Keyword',
|
||||
description: 'The main keyword to include in the product description',
|
||||
required: false,
|
||||
}),
|
||||
secondary_keywords: Property.LongText({
|
||||
displayName: 'Secondary Keywords',
|
||||
description:
|
||||
'Additional keywords to include in the product description, separated by commas',
|
||||
required: false,
|
||||
}),
|
||||
tone_of_voice: toneofvoiceDropdown,
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload: any = {
|
||||
product_name: context.propsValue.product_name,
|
||||
product_characteristics: context.propsValue.product_characteristics,
|
||||
};
|
||||
|
||||
if (context.propsValue.primary_keyword) {
|
||||
payload.primary_keyword = context.propsValue.primary_keyword;
|
||||
}
|
||||
if (context.propsValue.secondary_keywords) {
|
||||
payload.secondary_keywords = context.propsValue.secondary_keywords;
|
||||
}
|
||||
if (context.propsValue.tone_of_voice) {
|
||||
payload.tone_of_voice = context.propsValue.tone_of_voice;
|
||||
}
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/product-descriptions?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import {
|
||||
engineDropdownOptions,
|
||||
languageDropdownOptions,
|
||||
} from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const googleAds = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'googleAds',
|
||||
displayName: 'Google Ads',
|
||||
description:
|
||||
'Generate quality ads that rank in search results and drive more traffic',
|
||||
props: {
|
||||
product_name: Property.ShortText({
|
||||
displayName: 'Product Name',
|
||||
description: 'The name of the product or service to advertise',
|
||||
required: true,
|
||||
}),
|
||||
product_description: Property.LongText({
|
||||
displayName: 'Product Description',
|
||||
description: 'A brief description of the product or service',
|
||||
required: false,
|
||||
}),
|
||||
search_term: Property.ShortText({
|
||||
displayName: 'Search Term',
|
||||
description:
|
||||
'The search term or query to target in the Google Ads campaign',
|
||||
required: false,
|
||||
}),
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload: any = {
|
||||
product_name: context.propsValue.product_name,
|
||||
product_description: context.propsValue.product_description,
|
||||
search_term: context.propsValue.search_term,
|
||||
};
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/google-ads?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import {
|
||||
engineDropdownOptions,
|
||||
languageDropdownOptions,
|
||||
} from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const landingPageHeadlines = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'landingPageHeadlines',
|
||||
displayName: 'Landing Page Headlines',
|
||||
description:
|
||||
'Generate unique and catchy headlines perfect for your product or service',
|
||||
props: {
|
||||
product_name: Property.ShortText({
|
||||
displayName: 'Product Name',
|
||||
description: 'The name of the product or service',
|
||||
required: true,
|
||||
}),
|
||||
product_description: Property.LongText({
|
||||
displayName: 'Product Description',
|
||||
description: 'A brief description of the product or service',
|
||||
required: false,
|
||||
}),
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload: any = {
|
||||
product_name: context.propsValue.product_name,
|
||||
product_description: context.propsValue.product_description,
|
||||
};
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/landing-page-headlines?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { writesonicBulkAuth } from '../common/auth';
|
||||
import {
|
||||
engineDropdownOptions,
|
||||
languageDropdownOptions,
|
||||
toneofvoiceDropdown,
|
||||
} from '../common/props';
|
||||
import { makeRequest } from '../common/client';
|
||||
|
||||
export const sentenceExpander = createAction({
|
||||
auth: writesonicBulkAuth,
|
||||
name: 'sentenceExpander',
|
||||
displayName: 'Sentence Expander',
|
||||
description:
|
||||
'Expand short sentences into more descriptive and interesting ones',
|
||||
props: {
|
||||
content_to_expand: Property.LongText({
|
||||
displayName: 'Sentence',
|
||||
description: 'The sentence you want to expand',
|
||||
required: true,
|
||||
}),
|
||||
tone_of_voice: toneofvoiceDropdown,
|
||||
keyword: Property.ShortText({
|
||||
displayName: 'Keyword',
|
||||
description: 'A keyword to include in the expanded sentence',
|
||||
required: false,
|
||||
}),
|
||||
engine: engineDropdownOptions,
|
||||
language: languageDropdownOptions,
|
||||
num_copies: Property.Number({
|
||||
displayName: 'Number of Copies',
|
||||
description: 'Number of blog ideas to generate (1-5)',
|
||||
required: true,
|
||||
defaultValue: 1,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const payload: any = {
|
||||
content_to_expand: context.propsValue.content_to_expand,
|
||||
};
|
||||
if (context.propsValue.tone_of_voice) {
|
||||
payload.tone_of_voice = context.propsValue.tone_of_voice;
|
||||
}
|
||||
if (context.propsValue.keyword) {
|
||||
payload.keyword = context.propsValue.keyword;
|
||||
}
|
||||
const queryParams = new URLSearchParams({
|
||||
engine: context.propsValue.engine,
|
||||
language: context.propsValue.language,
|
||||
num_copies: context.propsValue.num_copies.toString(),
|
||||
});
|
||||
const response = await makeRequest(
|
||||
context.auth,
|
||||
HttpMethod.POST,
|
||||
`/content/sentence-expand?${queryParams.toString()}`,
|
||||
payload
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { PieceAuth } from '@activepieces/pieces-framework';
|
||||
|
||||
export const writesonicBulkAuth = PieceAuth.SecretText({
|
||||
displayName: 'Writesonic Bulk API Key',
|
||||
description: `
|
||||
To get your API Key:
|
||||
|
||||
1. Go to [app.writesonic.com](https://app.writesonic.com/)
|
||||
2. Login to your Writesonic account
|
||||
3. Hover over your display picture on the top-right corner to open the profile menu
|
||||
4. Click on "API Dashboard"
|
||||
5. Click on the switch to activate the API
|
||||
6. Click on "Reveal API Key"
|
||||
7. Copy and save your API key securely (never commit to public repositories)
|
||||
`,
|
||||
required: true,
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
import { AppConnectionValueForAuthProperty } from '@activepieces/pieces-framework';
|
||||
import { writesonicBulkAuth } from './auth';
|
||||
|
||||
export const BASE_URL = `https://api.writesonic.com/v2/business`;
|
||||
|
||||
export async function makeRequest(
|
||||
api_key: AppConnectionValueForAuthProperty<typeof writesonicBulkAuth>,
|
||||
method: HttpMethod,
|
||||
path: string,
|
||||
body?: unknown
|
||||
) {
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method,
|
||||
url: `${BASE_URL}${path}`,
|
||||
headers: {
|
||||
'X-API-KEY': `${api_key.secret_text}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body,
|
||||
});
|
||||
return response.body;
|
||||
} catch (error: any) {
|
||||
throw new Error(`Unexpected error: ${error.message || String(error)}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
|
||||
export const engineDropdownOptions = Property.StaticDropdown({
|
||||
displayName: 'Engine',
|
||||
description: 'Select the engine quality level',
|
||||
required: true,
|
||||
defaultValue: 'economy',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Economy', value: 'economy' },
|
||||
{ label: 'Average', value: 'average' },
|
||||
{ label: 'Good', value: 'good' },
|
||||
{ label: 'Premium', value: 'premium' },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export const languageDropdownOptions = Property.StaticDropdown({
|
||||
displayName: 'Language',
|
||||
description: 'Select the language',
|
||||
required: true,
|
||||
defaultValue: 'en',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'English', value: 'en' },
|
||||
{ label: 'Dutch', value: 'nl' },
|
||||
{ label: 'French', value: 'fr' },
|
||||
{ label: 'German', value: 'de' },
|
||||
{ label: 'Italian', value: 'it' },
|
||||
{ label: 'Polish', value: 'pl' },
|
||||
{ label: 'Spanish', value: 'es' },
|
||||
{ label: 'Portuguese (Portugal)', value: 'pt-pt' },
|
||||
{ label: 'Portuguese (Brazil)', value: 'pt-br' },
|
||||
{ label: 'Russian', value: 'ru' },
|
||||
{ label: 'Japanese', value: 'ja' },
|
||||
{ label: 'Chinese', value: 'zh' },
|
||||
{ label: 'Bulgarian', value: 'bg' },
|
||||
{ label: 'Czech', value: 'cs' },
|
||||
{ label: 'Danish', value: 'da' },
|
||||
{ label: 'Greek', value: 'el' },
|
||||
{ label: 'Hungarian', value: 'hu' },
|
||||
{ label: 'Lithuanian', value: 'lt' },
|
||||
{ label: 'Latvian', value: 'lv' },
|
||||
{ label: 'Romanian', value: 'ro' },
|
||||
{ label: 'Slovak', value: 'sk' },
|
||||
{ label: 'Slovenian', value: 'sl' },
|
||||
{ label: 'Swedish', value: 'sv' },
|
||||
{ label: 'Finnish', value: 'fi' },
|
||||
{ label: 'Estonian', value: 'et' },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export const toneofvoiceDropdown = Property.StaticDropdown({
|
||||
displayName: 'Tone of Voice',
|
||||
description: 'Select the tone of voice for the content',
|
||||
required: false,
|
||||
defaultValue: 'excited',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Excited', value: 'excited' },
|
||||
{ label: 'Professional', value: 'professional' },
|
||||
{ label: 'Funny', value: 'funny' },
|
||||
{ label: 'Encouraging', value: 'encouraging' },
|
||||
{ label: 'Dramatic', value: 'dramatic' },
|
||||
{ label: 'Witty', value: 'witty' },
|
||||
{ label: 'Sarcastic', value: 'sarcastic' },
|
||||
{ label: 'Engaging', value: 'engaging' },
|
||||
{ label: 'Creative', value: 'creative' },
|
||||
],
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user