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-camb-ai
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-camb-ai` to build the library.

View File

@@ -0,0 +1,11 @@
{
"name": "@activepieces/piece-camb-ai",
"version": "0.0.2",
"type": "commonjs",
"main": "./src/index.js",
"types": "./src/index.d.ts",
"dependencies": {
"form-data": "^4.0.4",
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,65 @@
{
"name": "pieces-camb-ai",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/camb-ai/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/camb-ai",
"tsConfig": "packages/pieces/community/camb-ai/tsconfig.lib.json",
"packageJson": "packages/pieces/community/camb-ai/package.json",
"main": "packages/pieces/community/camb-ai/src/index.ts",
"assets": [
"packages/pieces/community/camb-ai/*.md",
{
"input": "packages/pieces/community/camb-ai/src/i18n",
"output": "./src/i18n",
"glob": "**/!(i18n.json)"
}
],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true
},
"dependsOn": [
"^build",
"prebuild"
]
},
"nx-release-publish": {
"options": {
"packageRoot": "dist/{projectRoot}"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": [
"{options.outputFile}"
]
},
"prebuild": {
"executor": "nx:run-commands",
"options": {
"cwd": "packages/pieces/community/camb-ai",
"command": "bun install --no-save --silent"
},
"dependsOn": [
"^build"
]
}
}
}

View File

@@ -0,0 +1,68 @@
{
"\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ": "\n Um Ihren API-Schlüssel zu erhalten, folgen Sie bitte diesen Schritten:\n 1. Melde dich bei deinem [CAMB.AI Studio](https://camb.ai/studio/) Account an.\n 2. Navigieren Sie zur API-Tasten-Übersicht Ihres Arbeitsbereichs.\n 3. Erstellen Sie einen neuen Schlüssel, wenn Sie es noch nicht getan haben.\n 4. Kopieren Sie den API-Schlüssel und fügen Sie ihn hier ein.\n ",
"Create Text-to-Sound": "Text-to-Sound erstellen",
"Create Text-to-Speech": "Text-to-Speech erstellen",
"Create Translation": "Übersetzung erstellen",
"Create Transcription": "Transkription erstellen",
"Custom API Call": "Eigener API-Aufruf",
"Convert input text into “sound effects” using an AI model.": "Konvertieren Sie Eingabetext in „Soundeffekte“ mit Hilfe eines KI-Modells.",
"Convert text into speech using a specified voice, language, gender, and age group.": "Konvertieren Sie Text in Sprache mit einer bestimmten Stimme, Sprache, Geschlecht und Altersgruppe.",
"Translate text from a source language to a target language.": "Übersetze Text von einer Ausgangssprache in eine Zielsprache.",
"Creates a task to process speech into readable text.": "Erstellt eine Aufgabe, um die Sprache in lesbaren Text zu verarbeiten.",
"Make a custom API call to a specific endpoint": "Einen benutzerdefinierten API-Aufruf an einen bestimmten Endpunkt machen",
"Prompt": "Prompt",
"Duration (seconds)": "Dauer (Sekunden)",
"Project Name": "Projekt Name",
"Project Description": "Projektbeschreibung",
"Folder": "Ordner",
"Text": "Text",
"Source Language": "Quellsprache",
"Voice": "Stimme",
"Gender": "Geschlecht",
"Age": "Alter",
"Text to Translate": "Zu übersetzender Text",
"Target Language": "Zielsprache",
"Formality": "Formalität",
"Audience Age": "Alter des Publikums",
"Media Source": "Medienquelle",
"Media": "Medien",
"Method": "Methode",
"Headers": "Kopfzeilen",
"Query Parameters": "Abfrageparameter",
"Body": "Körper",
"Response is Binary ?": "Antwort ist binär?",
"No Error on Failure": "Kein Fehler bei Fehler",
"Timeout (in seconds)": "Timeout (in Sekunden)",
"A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.": "Eine klare, beschreibende Erklärung des gewünschten Audio-Effekts.",
"The desired length of the audio in seconds (max 10). Defaults to 8 if not set.": "Die gewünschte Audiolänge in Sekunden (max 10). Standardmäßig 8 wenn nicht gesetzt.",
"A memorable name for your project to help organize tasks in your Camb.ai workspace.": "Ein denkwürdiger Name für Ihr Projekt, um Aufgaben in Ihrem Camb.ai Arbeitsbereich zu organisieren.",
"Provide details about your project's goals and specifications for documentation purposes.": "Geben Sie zu Dokumentationszwecken Details zu den Zielen und Spezifikationen Ihres Projekts an.",
"Select the folder to save the task in.": "Wählen Sie den Ordner, in dem die Aufgabe gespeichert werden soll.",
"The text to be converted to speech.": "Der Text, der in eine Rede umgewandelt werden soll.",
"Select the original language of the input text.": "Wählen Sie die Originalsprache des Eingabetextes.",
"Select the voice to generate the speech.": "Wählen Sie die Stimme aus, um die Sprache zu generieren.",
"The gender of the speaker.": "Das Geschlecht des Redners.",
"The age of the speaker to be generated.": "Das Alter des zu erzeugenden Lautsprechers.",
"The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.": "Der zu übersetzende Text. Sie können mehrere Zeilen eingeben, jede Zeile wird als separates Textsegment behandelt.",
"Select the language to translate the text into.": "Wählen Sie die Sprache aus, in die der Text übersetzt werden soll.",
"Adjust the formality level to match your context.": "Passen Sie die Formalitätsstufe an, die Ihrem Kontext entspricht.",
"Specify grammatical gender preferences when relevant in the target language.": "Geben Sie grammatische Geschlechterpräferenzen an, wenn sie in der Zielsprache relevant sind.",
"Helps adjust vocabulary and expressions to be age-appropriate.": "Hilfe passt Vokabular und Ausdrücke altersgerecht an.",
"Choose whether to upload a file or provide a URL.": "Wählen Sie, ob eine Datei hochgeladen oder eine URL angegeben werden soll.",
"Authorization headers are injected automatically from your connection.": "Autorisierungs-Header werden automatisch von Ihrer Verbindung injiziert.",
"Enable for files like PDFs, images, etc..": "Aktivieren für Dateien wie PDFs, Bilder, etc..",
"Male": "Mann",
"Female": "Weiblich",
"Neutral": "Neutral",
"Unspecified": "Nicht angegeben",
"Formal": "Formal",
"Informal": "Informell",
"Upload File": "Datei hochladen",
"File URL": "Datei-URL",
"GET": "ERHALTEN",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "LÖSCHEN",
"HEAD": "HEAD"
}

View File

@@ -0,0 +1,68 @@
{
"\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ": "\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ",
"Create Text-to-Sound": "Crear texto a sonido",
"Create Text-to-Speech": "Crear texto a voz",
"Create Translation": "Crear traducción",
"Create Transcription": "Crear Transcripción",
"Custom API Call": "Llamada API personalizada",
"Convert input text into “sound effects” using an AI model.": "Convierte texto de entrada en \"efectos de sonido\" utilizando un modelo de IA.",
"Convert text into speech using a specified voice, language, gender, and age group.": "Convierte texto en voz usando una voz, idioma, género y grupo de edad.",
"Translate text from a source language to a target language.": "Traducir texto de un idioma de origen a un idioma de destino.",
"Creates a task to process speech into readable text.": "Crea una tarea para procesar el discurso en texto legible.",
"Make a custom API call to a specific endpoint": "Hacer una llamada API personalizada a un extremo específico",
"Prompt": "Petición",
"Duration (seconds)": "Duración (segundos)",
"Project Name": "Nombre del proyecto",
"Project Description": "Descripción del proyecto",
"Folder": "Carpeta",
"Text": "Texto",
"Source Language": "Idioma de origen",
"Voice": "Voz",
"Gender": "Sexo",
"Age": "Edad",
"Text to Translate": "Texto a traducir",
"Target Language": "Idioma de destino",
"Formality": "Formalidad",
"Audience Age": "Edad del público",
"Media Source": "Origen multimedia",
"Media": "Medios",
"Method": "Método",
"Headers": "Encabezados",
"Query Parameters": "Parámetros de consulta",
"Body": "Cuerpo",
"Response is Binary ?": "¿Respuesta es binaria?",
"No Error on Failure": "No hay ningún error en fallo",
"Timeout (in seconds)": "Tiempo de espera (en segundos)",
"A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.": "Una explicación clara y descriptiva del efecto de audio deseado.",
"The desired length of the audio in seconds (max 10). Defaults to 8 if not set.": "La longitud deseada del audio en segundos (máx. 10). Por defecto es 8 si no está definido.",
"A memorable name for your project to help organize tasks in your Camb.ai workspace.": "Un nombre memorable para su proyecto para ayudar a organizar tareas en su espacio de trabajo Camb.ai.",
"Provide details about your project's goals and specifications for documentation purposes.": "Proporcione detalles sobre los objetivos y especificaciones de su proyecto para fines de documentación.",
"Select the folder to save the task in.": "Seleccione la carpeta en la que guardar la tarea.",
"The text to be converted to speech.": "El texto que se convertirá en voz.",
"Select the original language of the input text.": "Seleccione el idioma original del texto de entrada.",
"Select the voice to generate the speech.": "Seleccione la voz para generar la voz.",
"The gender of the speaker.": "El género del orador.",
"The age of the speaker to be generated.": "La edad del orador que se generará.",
"The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.": "El texto a traducir. Puede introducir múltiples líneas; cada línea será tratada como un segmento de texto separado.",
"Select the language to translate the text into.": "Seleccione el idioma al que traducir el texto.",
"Adjust the formality level to match your context.": "Ajuste el nivel de formalidad para que coincida con su contexto.",
"Specify grammatical gender preferences when relevant in the target language.": "Especifique las preferencias de género gramaticales cuando sea relevante en el idioma de destino.",
"Helps adjust vocabulary and expressions to be age-appropriate.": "Ayuda a ajustar el vocabulario y las expresiones para que sean apropiadas para la edad.",
"Choose whether to upload a file or provide a URL.": "Elija si desea subir un archivo o proporcionar una URL.",
"Authorization headers are injected automatically from your connection.": "Las cabeceras de autorización se inyectan automáticamente desde tu conexión.",
"Enable for files like PDFs, images, etc..": "Activar para archivos como PDFs, imágenes, etc.",
"Male": "Hombre",
"Female": "Mujer",
"Neutral": "Neutral",
"Unspecified": "Sin especificar",
"Formal": "Formal",
"Informal": "Informal",
"Upload File": "Subir archivo",
"File URL": "URL del archivo",
"GET": "RECOGER",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "BORRAR",
"HEAD": "LIMPIO"
}

View File

@@ -0,0 +1,68 @@
{
"\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ": "\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ",
"Create Text-to-Sound": "Créer un texte à son",
"Create Text-to-Speech": "Créer un texte à voix",
"Create Translation": "Créer une traduction",
"Create Transcription": "Créer une transcription",
"Custom API Call": "Appel d'API personnalisé",
"Convert input text into “sound effects” using an AI model.": "Convertissez le texte en « effets sonores » en utilisant un modèle IA.",
"Convert text into speech using a specified voice, language, gender, and age group.": "Convertissez le texte en parole en utilisant une voix spécifiée, une langue, un sexe et un groupe d'âge.",
"Translate text from a source language to a target language.": "Traduire le texte d'une langue source vers une langue cible.",
"Creates a task to process speech into readable text.": "Crée une tâche pour traiter la parole en texte lisible.",
"Make a custom API call to a specific endpoint": "Passer un appel API personnalisé à un endpoint spécifique",
"Prompt": "Prompt",
"Duration (seconds)": "Durée (secondes)",
"Project Name": "Project Name",
"Project Description": "Description du projet",
"Folder": "Dossier",
"Text": "Texte du texte",
"Source Language": "Langue source",
"Voice": "Voix",
"Gender": "Sexe",
"Age": "Âge",
"Text to Translate": "Texte à traduire",
"Target Language": "Langue cible",
"Formality": "Formalité",
"Audience Age": "Âge du public",
"Media Source": "Media Source",
"Media": "Médias",
"Method": "Méthode",
"Headers": "Headers",
"Query Parameters": "Paramètres de requête",
"Body": "Body",
"Response is Binary ?": "La réponse est Binaire ?",
"No Error on Failure": "Aucune erreur en cas d'échec",
"Timeout (in seconds)": "Délai d'expiration (en secondes)",
"A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.": "Une explication claire et descriptive de l'effet audio désiré. Concise invite à produire des résultats plus précis.",
"The desired length of the audio in seconds (max 10). Defaults to 8 if not set.": "La longueur souhaitée de l'audio en secondes (max 10). Par défaut 8 si non défini.",
"A memorable name for your project to help organize tasks in your Camb.ai workspace.": "Un nom mémorable pour votre projet afin de vous aider à organiser des tâches dans votre espace de travail Camb.ai.",
"Provide details about your project's goals and specifications for documentation purposes.": "Fournissez des détails sur les objectifs et les spécifications de votre projet à des fins de documentation.",
"Select the folder to save the task in.": "Sélectionnez le dossier dans lequel enregistrer la tâche.",
"The text to be converted to speech.": "Le texte à convertir en discours.",
"Select the original language of the input text.": "Sélectionnez la langue d'origine du texte de saisie.",
"Select the voice to generate the speech.": "Sélectionnez la voix pour générer le discours.",
"The gender of the speaker.": "Le sexe de l'orateur.",
"The age of the speaker to be generated.": "L'âge de l'orateur à générer.",
"The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.": "Le texte à traduire. Vous pouvez entrer plusieurs lignes; chaque ligne sera traitée comme un segment de texte séparé.",
"Select the language to translate the text into.": "Sélectionnez la langue dans laquelle traduire le texte.",
"Adjust the formality level to match your context.": "Ajustez le niveau de formalité pour correspondre à votre contexte.",
"Specify grammatical gender preferences when relevant in the target language.": "Spécifiez les préférences grammaticales de genre quand elles sont pertinentes dans la langue cible.",
"Helps adjust vocabulary and expressions to be age-appropriate.": "Aide à ajuster le vocabulaire et les expressions en fonction de l'âge.",
"Choose whether to upload a file or provide a URL.": "Choisissez si vous souhaitez télécharger un fichier ou fournir une URL.",
"Authorization headers are injected automatically from your connection.": "Les Headers d'autorisation sont injectés automatiquement à partir de votre connexion.",
"Enable for files like PDFs, images, etc..": "Activer pour les fichiers comme les PDFs, les images, etc.",
"Male": "Homme",
"Female": "Femme",
"Neutral": "Neutre",
"Unspecified": "Non spécifié",
"Formal": "Formale",
"Informal": "Informel",
"Upload File": "Charger un fichier",
"File URL": "URL du fichier",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD"
}

View File

@@ -0,0 +1,68 @@
{
"\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ": "\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ",
"Create Text-to-Sound": "テキストからサウンドへの作成",
"Create Text-to-Speech": "テキスト読み上げの作成",
"Create Translation": "翻訳を作成",
"Create Transcription": "表記を作成",
"Custom API Call": "カスタムAPI通話",
"Convert input text into “sound effects” using an AI model.": "AIモデルを使用して入力テキストを「効果音」に変換します。",
"Convert text into speech using a specified voice, language, gender, and age group.": "指定した音声、言語、性別、年齢グループを使用してテキストを音声に変換します。",
"Translate text from a source language to a target language.": "翻訳元の言語からターゲット言語にテキストを翻訳します。",
"Creates a task to process speech into readable text.": "読み取り可能なテキストに音声を処理するタスクを作成します。",
"Make a custom API call to a specific endpoint": "特定のエンドポイントへのカスタム API コールを実行します。",
"Prompt": "Prompt",
"Duration (seconds)": "期間 (秒)",
"Project Name": "プロジェクト名",
"Project Description": "プロジェクトの説明",
"Folder": "Folder",
"Text": "テキスト",
"Source Language": "ソース言語",
"Voice": "音声",
"Gender": "性別",
"Age": "年齢",
"Text to Translate": "翻訳するテキスト",
"Target Language": "翻訳先言語",
"Formality": "Formatality",
"Audience Age": "オーディエンス年齢",
"Media Source": "メディアソース",
"Media": "メディア",
"Method": "方法",
"Headers": "ヘッダー",
"Query Parameters": "クエリパラメータ",
"Body": "本文",
"Response is Binary ?": "応答はバイナリですか?",
"No Error on Failure": "失敗時にエラーはありません",
"Timeout (in seconds)": "タイムアウト(秒)",
"A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.": "目的のオーディオエフェクトの明確な説明。より正確な結果が得られるように促します。",
"The desired length of the audio in seconds (max 10). Defaults to 8 if not set.": "オーディオの任意の長さを秒単位で指定します。設定されていない場合、デフォルトは 8 です。",
"A memorable name for your project to help organize tasks in your Camb.ai workspace.": "Camb.aiワークスペースでタスクを整理するのに役立つプロジェクトの思い出に残る名前。",
"Provide details about your project's goals and specifications for documentation purposes.": "あなたのプロジェクトの目標とドキュメントの目的のための仕様についての詳細を提供します。",
"Select the folder to save the task in.": "タスクを保存するフォルダーを選択します。",
"The text to be converted to speech.": "音声に変換されるテキスト。",
"Select the original language of the input text.": "入力テキストの元の言語を選択します。",
"Select the voice to generate the speech.": "音声を生成する音声を選択します。",
"The gender of the speaker.": "スピーカーの性別。",
"The age of the speaker to be generated.": "生成するスピーカーの年齢。",
"The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.": "翻訳するテキスト。複数行を入力することができます。各行は個別のテキストセグメントとして扱われます。",
"Select the language to translate the text into.": "テキストを翻訳する言語を選択します。",
"Adjust the formality level to match your context.": "文脈に合わせて形式レベルを調整します。",
"Specify grammatical gender preferences when relevant in the target language.": "ターゲット言語に関連する文法上の性別設定を指定します。",
"Helps adjust vocabulary and expressions to be age-appropriate.": "ボキャブラリーや表現の調整に役立ちます。",
"Choose whether to upload a file or provide a URL.": "ファイルをアップロードするか、URLを指定するかを選択します。",
"Authorization headers are injected automatically from your connection.": "認証ヘッダは接続から自動的に注入されます。",
"Enable for files like PDFs, images, etc..": "PDF、画像などのファイルを有効にします。",
"Male": "男性",
"Female": "女性",
"Neutral": "ニュートラル",
"Unspecified": "未指定",
"Formal": "Formal",
"Informal": "非公式な",
"Upload File": "ファイルをアップロード",
"File URL": "ファイル URL",
"GET": "取得",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "削除",
"HEAD": "頭"
}

View File

@@ -0,0 +1,68 @@
{
"\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ": "\n Om uw API-sleutel te krijgen, volg de volgende stappen:\n 1. Log in op je [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigeer naar het dashboard van de API-sleutels.\n 3. Creëer een nieuwe sleutel als je dat nog niet gedaan hebt.\n 4. Kopieer en plak de API-sleutel hier.\n ",
"Create Text-to-Sound": "Text-to-Sound aanmaken",
"Create Text-to-Speech": "Maak tekst-naar-spraak",
"Create Translation": "Vertaling aanmaken",
"Create Transcription": "Transcriptie aanmaken",
"Custom API Call": "Custom API Call",
"Convert input text into “sound effects” using an AI model.": "Zet tekst om in \"geluidseffecten\" met behulp van een AI-model.",
"Convert text into speech using a specified voice, language, gender, and age group.": "Zet tekst om in spraak met een bepaalde stem, taal, geslacht en leeftijdsgroep.",
"Translate text from a source language to a target language.": "Vertaal tekst van een brontaal naar een doeltaal.",
"Creates a task to process speech into readable text.": "Maakt een taak om spraak in leesbare tekst te verwerken.",
"Make a custom API call to a specific endpoint": "Maak een aangepaste API call naar een specifiek eindpunt",
"Prompt": "Prompt",
"Duration (seconds)": "Duur (seconden)",
"Project Name": "Projectnaam",
"Project Description": "Project beschrijving",
"Folder": "Map",
"Text": "Tekstveld",
"Source Language": "Bron taal",
"Voice": "Stem",
"Gender": "Geslacht",
"Age": "Leeftijd",
"Text to Translate": "Tekst te vertalen",
"Target Language": "Doel taal",
"Formality": "Formaliteit",
"Audience Age": "Audience Leeftijd",
"Media Source": "Media Bron",
"Media": "Medium",
"Method": "Methode",
"Headers": "Kopteksten",
"Query Parameters": "Query parameters",
"Body": "Lichaam",
"Response is Binary ?": "Antwoord is binair?",
"No Error on Failure": "Geen fout bij fout",
"Timeout (in seconds)": "Time-out (in seconden)",
"A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.": "Een duidelijke, beschrijvende uitleg van het gewenste audio-effect. Concise zorgt voor nauwkeurigere resultaten.",
"The desired length of the audio in seconds (max 10). Defaults to 8 if not set.": "De gewenste lengte van de audio in seconden (max 10). Standaard ingesteld op 8 indien niet ingesteld.",
"A memorable name for your project to help organize tasks in your Camb.ai workspace.": "Een memorabele naam voor uw project om taken te organiseren in uw Camb.ai werkruimte.",
"Provide details about your project's goals and specifications for documentation purposes.": "Geef details over de doelen en specificaties van uw project voor documentatiedoeleinden.",
"Select the folder to save the task in.": "Selecteer de map waarin de taak moet worden opgeslagen.",
"The text to be converted to speech.": "De tekst die moet worden omgezet in woorden.",
"Select the original language of the input text.": "Selecteer de originele taal van de invoertekst.",
"Select the voice to generate the speech.": "Selecteer de stem om de toespraak te genereren.",
"The gender of the speaker.": "Het geslacht van de spreker.",
"The age of the speaker to be generated.": "De leeftijd van de spreker die wordt gegenereerd.",
"The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.": "De te vertalen tekst. U kunt meerdere regels invoeren; elke regel wordt behandeld als een apart tekstsegment.",
"Select the language to translate the text into.": "Selecteer de taal waar de tekst naartoe moet worden vertaald.",
"Adjust the formality level to match your context.": "Pas het formaliteitsniveau aan om aan uw context te voldoen.",
"Specify grammatical gender preferences when relevant in the target language.": "Geef grammaticale gendervoorkeuren op wanneer relevant in de doeltaal.",
"Helps adjust vocabulary and expressions to be age-appropriate.": "Helpen aanpassen aan woordenschat en uitdrukkingen naar leeftijd.",
"Choose whether to upload a file or provide a URL.": "Kies of een bestand moet worden geüpload of een URL moet worden ingevuld.",
"Authorization headers are injected automatically from your connection.": "Autorisatie headers worden automatisch geïnjecteerd vanuit uw verbinding.",
"Enable for files like PDFs, images, etc..": "Inschakelen voor bestanden zoals PDF's, afbeeldingen etc..",
"Male": "Mannelijk",
"Female": "Vrouwelijk",
"Neutral": "Neutraal",
"Unspecified": "Ongespecificeerd",
"Formal": "Formeel",
"Informal": "Informeel",
"Upload File": "Bestand uploaden",
"File URL": "Bestand URL",
"GET": "KRIJG",
"POST": "POSTE",
"PATCH": "BEKIJK",
"PUT": "PUT",
"DELETE": "VERWIJDEREN",
"HEAD": "HOOFD"
}

View File

@@ -0,0 +1,68 @@
{
"\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ": "\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ",
"Create Text-to-Sound": "Criar texto-para-som",
"Create Text-to-Speech": "Criar texto-para-voz",
"Create Translation": "Criar tradução",
"Create Transcription": "Criar Transcrição",
"Custom API Call": "Chamada de API personalizada",
"Convert input text into “sound effects” using an AI model.": "Converter texto de entrada em \"efeitos de som\" usando um modelo de IA.",
"Convert text into speech using a specified voice, language, gender, and age group.": "Converta texto em fala usando uma determinada voz, idioma, gênero e faixa etária.",
"Translate text from a source language to a target language.": "Traduzir o texto de um idioma de origem para um idioma de destino.",
"Creates a task to process speech into readable text.": "Cria uma tarefa para processar a fala em texto legível.",
"Make a custom API call to a specific endpoint": "Faça uma chamada de API personalizada para um ponto de extremidade específico",
"Prompt": "Aviso",
"Duration (seconds)": "Duração (segundos)",
"Project Name": "Nome do Projeto",
"Project Description": "Descrição do Projeto",
"Folder": "Pasta",
"Text": "texto",
"Source Language": "Língua Original",
"Voice": "Voz",
"Gender": "Gênero",
"Age": "Idade",
"Text to Translate": "Texto para traduzir",
"Target Language": "Idioma de destino",
"Formality": "Formaldade",
"Audience Age": "Era da audiência",
"Media Source": "Fonte de Mídia",
"Media": "Multimídia",
"Method": "Método",
"Headers": "Cabeçalhos",
"Query Parameters": "Parâmetros da consulta",
"Body": "Conteúdo",
"Response is Binary ?": "A resposta é binária ?",
"No Error on Failure": "Nenhum erro no Failure",
"Timeout (in seconds)": "Tempo limite (em segundos)",
"A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.": "Uma explicação clara e descritiva do efeito de áudio desejado. Prompts concisos produzem resultados mais precisos.",
"The desired length of the audio in seconds (max 10). Defaults to 8 if not set.": "O comprimento desejado do áudio em segundos (máximo 10). O padrão é 8, se não for definido.",
"A memorable name for your project to help organize tasks in your Camb.ai workspace.": "Um nome memorável para seu projeto ajudar a organizar tarefas no seu espaço de trabalho do Camb.ai.",
"Provide details about your project's goals and specifications for documentation purposes.": "Forneça detalhes sobre metas e especificações de seu projeto para fins de documentação.",
"Select the folder to save the task in.": "Selecione a pasta para salvar a tarefa",
"The text to be converted to speech.": "O texto a ser convertido em fala.",
"Select the original language of the input text.": "Selecione o idioma original do texto de entrada.",
"Select the voice to generate the speech.": "Selecione a voz para gerar a fala.",
"The gender of the speaker.": "O género do orador.",
"The age of the speaker to be generated.": "A idade do orador a gerar.",
"The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.": "O texto a ser traduzido. Você pode inserir várias linhas; cada linha será tratada como um segmento de texto separado.",
"Select the language to translate the text into.": "Selecione o idioma para traduzir o texto.",
"Adjust the formality level to match your context.": "Ajuste o nível de formalidade para corresponder ao seu contexto.",
"Specify grammatical gender preferences when relevant in the target language.": "Especifique preferências gramaticais de gênero quando relevante no idioma de destino.",
"Helps adjust vocabulary and expressions to be age-appropriate.": "Ajuda a ajustar vocabulário e expressões para serem apropriadas.",
"Choose whether to upload a file or provide a URL.": "Escolha se deseja enviar um arquivo ou fornecer uma URL.",
"Authorization headers are injected automatically from your connection.": "Os cabeçalhos de autorização são inseridos automaticamente a partir da sua conexão.",
"Enable for files like PDFs, images, etc..": "Habilitar para arquivos como PDFs, imagens, etc..",
"Male": "Masculino",
"Female": "Feminino",
"Neutral": "Neutro",
"Unspecified": "Não-especificado",
"Formal": "Formal",
"Informal": "Informal",
"Upload File": "Enviar Arquivo",
"File URL": "URL do Arquivo",
"GET": "OBTER",
"POST": "POSTAR",
"PATCH": "COMPRAR",
"PUT": "COLOCAR",
"DELETE": "EXCLUIR",
"HEAD": "CABEÇA"
}

View File

@@ -0,0 +1,68 @@
{
"\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ": "\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ",
"Create Text-to-Sound": "Create Text-to-Sound",
"Create Text-to-Speech": "Create Text-to-Speech",
"Create Translation": "Create Translation",
"Create Transcription": "Create Transcription",
"Custom API Call": "Custom API Call",
"Convert input text into “sound effects” using an AI model.": "Convert input text into “sound effects” using an AI model.",
"Convert text into speech using a specified voice, language, gender, and age group.": "Convert text into speech using a specified voice, language, gender, and age group.",
"Translate text from a source language to a target language.": "Translate text from a source language to a target language.",
"Creates a task to process speech into readable text.": "Creates a task to process speech into readable text.",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Prompt": "Prompt",
"Duration (seconds)": "Duration (seconds)",
"Project Name": "Project Name",
"Project Description": "Project Description",
"Folder": "Folder",
"Text": "Text",
"Source Language": "Source Language",
"Voice": "Voice",
"Gender": "Gender",
"Age": "Age",
"Text to Translate": "Text to Translate",
"Target Language": "Target Language",
"Formality": "Formality",
"Audience Age": "Audience Age",
"Media Source": "Media Source",
"Media": "Media",
"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)",
"A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.": "A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.",
"The desired length of the audio in seconds (max 10). Defaults to 8 if not set.": "The desired length of the audio in seconds (max 10). Defaults to 8 if not set.",
"A memorable name for your project to help organize tasks in your Camb.ai workspace.": "A memorable name for your project to help organize tasks in your Camb.ai workspace.",
"Provide details about your project's goals and specifications for documentation purposes.": "Provide details about your project's goals and specifications for documentation purposes.",
"Select the folder to save the task in.": "Select the folder to save the task in.",
"The text to be converted to speech.": "The text to be converted to speech.",
"Select the original language of the input text.": "Select the original language of the input text.",
"Select the voice to generate the speech.": "Select the voice to generate the speech.",
"The gender of the speaker.": "The gender of the speaker.",
"The age of the speaker to be generated.": "The age of the speaker to be generated.",
"The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.": "The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.",
"Select the language to translate the text into.": "Select the language to translate the text into.",
"Adjust the formality level to match your context.": "Adjust the formality level to match your context.",
"Specify grammatical gender preferences when relevant in the target language.": "Specify grammatical gender preferences when relevant in the target language.",
"Helps adjust vocabulary and expressions to be age-appropriate.": "Helps adjust vocabulary and expressions to be age-appropriate.",
"Choose whether to upload a file or provide a URL.": "Choose whether to upload a file or provide a URL.",
"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..",
"Male": "Male",
"Female": "Female",
"Neutral": "Neutral",
"Unspecified": "Unspecified",
"Formal": "Formal",
"Informal": "Informal",
"Upload File": "Upload File",
"File URL": "File URL",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD"
}

View File

@@ -0,0 +1,68 @@
{
"\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ": "\n To get your API key, please follow these steps:\n 1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.\n 2. Navigate to your workspace's API Keys dashboard.\n 3. Create a new key if you haven't already.\n 4. Copy the API key and paste it here.\n ",
"Create Text-to-Sound": "Create Text-to-Sound",
"Create Text-to-Speech": "Create Text-to-Speech",
"Create Translation": "Create Translation",
"Create Transcription": "Create Transcription",
"Custom API Call": "自定义 API 呼叫",
"Convert input text into “sound effects” using an AI model.": "Convert input text into “sound effects” using an AI model.",
"Convert text into speech using a specified voice, language, gender, and age group.": "Convert text into speech using a specified voice, language, gender, and age group.",
"Translate text from a source language to a target language.": "Translate text from a source language to a target language.",
"Creates a task to process speech into readable text.": "Creates a task to process speech into readable text.",
"Make a custom API call to a specific endpoint": "将一个自定义 API 调用到一个特定的终点",
"Prompt": "Prompt",
"Duration (seconds)": "Duration (seconds)",
"Project Name": "项目名称",
"Project Description": "Project Description",
"Folder": "Folder",
"Text": "文本",
"Source Language": "Source Language",
"Voice": "Voice",
"Gender": "Gender",
"Age": "Age",
"Text to Translate": "Text to Translate",
"Target Language": "Target Language",
"Formality": "Formality",
"Audience Age": "Audience Age",
"Media Source": "Media Source",
"Media": "Media",
"Method": "方法",
"Headers": "信头",
"Query Parameters": "查询参数",
"Body": "正文内容",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "失败时没有错误",
"Timeout (in seconds)": "超时(秒)",
"A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.": "A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.",
"The desired length of the audio in seconds (max 10). Defaults to 8 if not set.": "The desired length of the audio in seconds (max 10). Defaults to 8 if not set.",
"A memorable name for your project to help organize tasks in your Camb.ai workspace.": "A memorable name for your project to help organize tasks in your Camb.ai workspace.",
"Provide details about your project's goals and specifications for documentation purposes.": "Provide details about your project's goals and specifications for documentation purposes.",
"Select the folder to save the task in.": "Select the folder to save the task in.",
"The text to be converted to speech.": "The text to be converted to speech.",
"Select the original language of the input text.": "Select the original language of the input text.",
"Select the voice to generate the speech.": "Select the voice to generate the speech.",
"The gender of the speaker.": "The gender of the speaker.",
"The age of the speaker to be generated.": "The age of the speaker to be generated.",
"The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.": "The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.",
"Select the language to translate the text into.": "Select the language to translate the text into.",
"Adjust the formality level to match your context.": "Adjust the formality level to match your context.",
"Specify grammatical gender preferences when relevant in the target language.": "Specify grammatical gender preferences when relevant in the target language.",
"Helps adjust vocabulary and expressions to be age-appropriate.": "Helps adjust vocabulary and expressions to be age-appropriate.",
"Choose whether to upload a file or provide a URL.": "Choose whether to upload a file or provide a URL.",
"Authorization headers are injected automatically from your connection.": "授权头自动从您的连接中注入。",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"Male": "Male",
"Female": "Female",
"Neutral": "Neutral",
"Unspecified": "Unspecified",
"Formal": "Formal",
"Informal": "Informal",
"Upload File": "Upload File",
"File URL": "File URL",
"GET": "获取",
"POST": "帖子",
"PATCH": "PATCH",
"PUT": "弹出",
"DELETE": "删除",
"HEAD": "黑色"
}

View File

@@ -0,0 +1,64 @@
import { PieceAuth, createPiece } from "@activepieces/pieces-framework";
import { createCustomApiCallAction, httpClient, HttpMethod } from "@activepieces/pieces-common";
import { createTextToSound } from "./lib/actions/create-text-to-sound";
import { createTextToSpeech } from "./lib/actions/create-text-to-speech";
import { createTranslation } from "./lib/actions/create-translation";
import { createTranscription } from "./lib/actions/create-transcription";
import { API_BASE_URL } from "./lib/common";
import { PieceCategory } from "@activepieces/shared";
export const cambaiAuth = PieceAuth.SecretText({
displayName: "API Key",
description: `
To get your API key, please follow these steps:
1. Log in to your [CAMB.AI Studio](https://camb.ai/studio/) account.
2. Navigate to your workspace's API Keys dashboard.
3. Create a new key if you haven't already.
4. Copy the API key and paste it here.
`,
required: true,
validate: async ({ auth }) => {
try {
await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${API_BASE_URL}/source-languages`,
headers: {
'x-api-key': auth,
}
});
return {
valid: true,
};
} catch (e) {
return {
valid: false,
error: 'Invalid API Key.',
};
}
}
});
export const cambAi = createPiece({
displayName: "Camb.AI",
auth: cambaiAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: "https://cdn.activepieces.com/pieces/camb-ai.png",
authors: ['david-oluwaseun420','sanket-a11y'],
categories:[PieceCategory.ARTIFICIAL_INTELLIGENCE],
actions: [
createTextToSound,
createTextToSpeech,
createTranslation,
createTranscription,
createCustomApiCallAction({
auth: cambaiAuth,
baseUrl: () => API_BASE_URL,
authMapping: async (auth) => {
return {
'x-api-key': auth.secret_text,
};
},
}),
],
triggers: [],
});

View File

@@ -0,0 +1,102 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { cambaiAuth } from '../../index';
import { API_BASE_URL, MAX_POLLING_ATTEMPTS, POLLING_INTERVAL_MS } from '../common';
import { listFoldersDropdown } from '../common';
export const createTextToSound = createAction({
auth: cambaiAuth,
name: 'create_text_to_sound',
displayName: 'Create Text-to-Sound',
description: 'Convert input text into “sound effects” using an AI model.',
props: {
prompt: Property.LongText({
displayName: 'Prompt',
description: 'A clear, descriptive explanation of the desired audio effect. Concise prompts yield more accurate results.',
required: true,
}),
duration: Property.Number({
displayName: 'Duration (seconds)',
description: 'The desired length of the audio in seconds (max 10). Defaults to 8 if not set.',
required: false,
}),
project_name: Property.ShortText({
displayName: 'Project Name',
description: 'A memorable name for your project to help organize tasks in your Camb.ai workspace.',
required: false,
}),
project_description: Property.LongText({
displayName: 'Project Description',
description: 'Provide details about your project\'s goals and specifications for documentation purposes.',
required: false,
}),
folder_id: listFoldersDropdown,
},
async run(context) {
const { auth } = context;
const { prompt, duration, project_name, project_description, folder_id } = context.propsValue;
const payload: Record<string, unknown> = { prompt };
if (duration) payload['duration'] = duration;
if (project_name) payload['project_name'] = project_name;
if (project_description) payload['project_description'] = project_description;
if (folder_id) payload['folder_id'] = folder_id;
const initialResponse = await httpClient.sendRequest<{ task_id: string }>({
method: HttpMethod.POST,
url: `${API_BASE_URL}/text-to-sound`,
headers: {
'x-api-key': auth.secret_text,
'Content-Type': 'application/json'
},
body: payload,
});
const taskId = initialResponse.body.task_id;
let attempts = 0;
let run_id: string | null = null;
while (attempts < MAX_POLLING_ATTEMPTS) {
const statusResponse = await httpClient.sendRequest<{
status: string, run_id?: string
}>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/text-to-sound/${taskId}`,
headers: {
'x-api-key': auth.secret_text,
},
});
const status = statusResponse.body.status;
if (status === 'SUCCESS') {
run_id = statusResponse.body.run_id ?? null;
break;
}
if (status === 'FAILED') {
throw new Error(`Sound generation task failed: ${JSON.stringify(statusResponse.body)}`);
}
await new Promise(resolve => setTimeout(resolve, POLLING_INTERVAL_MS));
attempts++;
}
if (!run_id) {
throw new Error("Sound generation task timed out or failed to return a run_id.");
}
const audioResponse = await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${API_BASE_URL}/text-to-sound-result/${run_id}`,
headers: { 'x-api-key': auth.secret_text },
responseType: 'arraybuffer',
});
return { audio: audioResponse.body };
},
});

View File

@@ -0,0 +1,119 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod, httpClient, HttpResponse } from '@activepieces/pieces-common';
import { cambaiAuth } from '../../index';
import { API_BASE_URL, listSourceLanguagesDropdown, listVoicesDropdown ,POLLING_INTERVAL_MS,MAX_POLLING_ATTEMPTS } from '../common';
import { listFoldersDropdown } from '../common';
export const createTextToSpeech = createAction({
auth: cambaiAuth,
name: 'create_text_to_speech',
displayName: 'Create Text-to-Speech',
description: 'Convert text into speech using a specified voice, language, gender, and age group.',
props: {
text: Property.LongText({
displayName: 'Text',
description: 'The text to be converted to speech.',
required: true,
}),
language: listSourceLanguagesDropdown,
voice_id: listVoicesDropdown,
gender: Property.StaticDropdown({
displayName: 'Gender',
description: 'The gender of the speaker.',
required: false,
options: {
options: [
{ label: 'Male', value: 1 },
{ label: 'Female', value: 2 },
{ label: 'Neutral', value: 0 },
{ label: 'Unspecified', value: 9 },
],
}
}),
age: Property.Number({
displayName: 'Age',
description: 'The age of the speaker to be generated.',
required: false,
}),
project_name: Property.ShortText({
displayName: 'Project Name',
description: 'A memorable name for your project to help organize tasks in your Camb.ai workspace.',
required: false,
}),
project_description: Property.LongText({
displayName: 'Project Description',
description: 'Provide details about your project\'s goals and specifications for documentation purposes.',
required: false,
}),
folder_id: listFoldersDropdown,
},
async run(context) {
const { auth } = context;
const { text, language, voice_id, gender, age, project_name, project_description, folder_id } = context.propsValue;
const payload: Record<string, unknown> = { text, language: Number(language), voice_id: Number(voice_id) };
if (gender !== undefined) payload['gender'] = gender;
if (age) payload['age'] = age;
if (project_name) payload['project_name'] = project_name;
if (project_description) payload['project_description'] = project_description;
if (folder_id) payload['folder_id'] = folder_id;
const initialResponse = await httpClient.sendRequest<{ task_id: string }>({
method: HttpMethod.POST,
url: `${API_BASE_URL}/tts`,
headers: { 'x-api-key': auth.secret_text, 'Content-Type': 'application/json' },
body: payload,
});
const taskId = initialResponse.body.task_id;
let attempts = 0;
let run_id: string | null = null;
while (attempts < MAX_POLLING_ATTEMPTS) {
const statusResponse = await httpClient.sendRequest<{ status: string; run_id?: string }>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/tts/${taskId}`,
headers: { 'x-api-key': auth.secret_text },
});
if (statusResponse.body.status === 'SUCCESS') {
run_id = statusResponse.body.run_id ?? null;
break;
}
if (statusResponse.body.status === 'FAILED') {
throw new Error(`Text-to-Speech task failed: ${JSON.stringify(statusResponse.body)}`);
}
await new Promise(resolve => setTimeout(resolve, POLLING_INTERVAL_MS));
attempts++;
}
if (!run_id) {
throw new Error("Text-to-Speech task timed out or failed to return a run_id.");
}
const audioResponse: HttpResponse = await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${API_BASE_URL}/tts-result/${run_id}`,
headers: { 'x-api-key': auth.secret_text },
responseType: 'arraybuffer',
});
const fileName = `speech_${run_id}.wav`;
const fileData = Buffer.from(audioResponse.body as ArrayBuffer);
const fileUrl = await context.files.write({
fileName,
data: fileData,
});
return {
message: "Speech generated successfully.",
audio_url: fileUrl,
run_id: run_id,
};
},
});

View File

@@ -0,0 +1,130 @@
import { createAction, Property, ApFile, DynamicPropsValue } from '@activepieces/pieces-framework';
import { HttpMethod, httpClient, HttpMessageBody, HttpHeaders } from '@activepieces/pieces-common';
import { cambaiAuth } from '../../index';
import { API_BASE_URL, listSourceLanguagesDropdown, POLLING_INTERVAL_MS, LONG_MAX_POLLING_ATTEMPTS } from '../common';
import FormData from 'form-data';
import { listFoldersDropdown } from '../common';
export const createTranscription = createAction({
auth: cambaiAuth,
name: 'create_transcription',
displayName: 'Create Transcription',
description: 'Creates a task to process speech into readable text.',
props: {
language: listSourceLanguagesDropdown,
source_type: Property.StaticDropdown({
displayName: 'Media Source',
description: 'Choose whether to upload a file or provide a URL.',
required: true,
defaultValue: 'file',
options: {
options: [
{ label: 'Upload File', value: 'file' },
{ label: 'File URL', value: 'url' },
]
},
}),
media: Property.DynamicProperties({
auth: cambaiAuth,
displayName: 'Media',
required: true,
refreshers: ['source_type'],
props: async (context) => {
const sourceType = (context['source_type'] as unknown as string);
const fields: DynamicPropsValue = {};
if (sourceType === 'file') {
fields['media_file'] = Property.File({
displayName: 'Media File',
description: 'The media file (e.g., MP3, WAV, MP4) to transcribe. Max size: 20MB.',
required: true,
});
} else if (sourceType === 'url') {
fields['media_url'] = Property.ShortText({
displayName: 'Media URL',
description: 'A public URL to the media file to transcribe.',
required: true,
});
}
return fields;
}
}),
project_name: Property.ShortText({
displayName: 'Project Name',
description: 'A memorable name for your project to help organize tasks in your Camb.ai workspace.',
required: false,
}),
project_description: Property.LongText({
displayName: 'Project Description',
description: 'Provide details about your project\'s goals and specifications for documentation purposes.',
required: false,
}),
folder_id: listFoldersDropdown,
},
async run(context) {
const { auth } = context;
const { language, source_type, media, project_name, project_description, folder_id } = context.propsValue;
const formData = new FormData();
formData.append('language', Number(language).toString());
if (project_name) formData.append('project_name', project_name);
if (project_description) formData.append('project_description', project_description);
if (folder_id) formData.append('folder_id', folder_id.toString());
if (source_type === 'url') {
if (!media['media_url']) throw new Error("Media URL is required when source is 'File URL'.");
formData.append('media_url', media['media_url'] as string);
} else {
if (!media['media_file']) throw new Error("Media File is required when source is 'Upload File'.");
const fileData = media['media_file'] as ApFile;
formData.append('media_file', fileData.data, fileData.filename);
}
const requestBody = await formData.getBuffer();
const headers: HttpHeaders = {
'x-api-key': auth.secret_text,
...formData.getHeaders(),
};
const initialResponse = await httpClient.sendRequest<{ task_id: string }>({
method: HttpMethod.POST,
url: `${API_BASE_URL}/transcribe`,
headers: headers,
body: requestBody,
});
const taskId = initialResponse.body.task_id;
let run_id: string | null = null;
let attempts = 0;
while (attempts < LONG_MAX_POLLING_ATTEMPTS) {
const statusResponse = await httpClient.sendRequest<{ status: string; run_id?: string }>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/transcribe/${taskId}`,
headers: { 'x-api-key': auth.secret_text },
});
if (statusResponse.body.status === 'SUCCESS') {
run_id = statusResponse.body.run_id ?? null;
break;
}
if (statusResponse.body.status === 'FAILED') {
throw new Error(`Transcription task failed: ${JSON.stringify(statusResponse.body)}`);
}
await new Promise(resolve => setTimeout(resolve, POLLING_INTERVAL_MS));
attempts++;
}
if (!run_id) {
throw new Error("Transcription task timed out or failed to return a task_id.");
}
const resultResponse = await httpClient.sendRequest<{ transcriptions: string[] }>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/transcription-result/${run_id}`,
headers: { 'x-api-key': auth.secret_text },
});
return resultResponse.body;
},
});

View File

@@ -0,0 +1,113 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
import { cambaiAuth } from '../../index';
import { API_BASE_URL, listSourceLanguagesDropdown, listTargetLanguagesDropdown ,POLLING_INTERVAL_MS,MAX_POLLING_ATTEMPTS} from '../common';
export const createTranslation = createAction({
auth: cambaiAuth,
name: 'create_translation',
displayName: 'Create Translation',
description: 'Translate text from a source language to a target language.',
props: {
texts: Property.LongText({
displayName: 'Text to Translate',
description: 'The text to be translated. You can enter multiple lines; each line will be treated as a separate text segment.',
required: true,
}),
source_language: listSourceLanguagesDropdown,
target_language: listTargetLanguagesDropdown,
formality: Property.StaticDropdown({
displayName: 'Formality',
description: 'Adjust the formality level to match your context.',
required: false,
options: {
options: [
{ label: 'Formal', value: 1 },
{ label: 'Informal', value: 2 },
]
}
}),
gender: Property.StaticDropdown({
displayName: 'Gender',
description: 'Specify grammatical gender preferences when relevant in the target language.',
required: false,
options: {
options: [
{ label: 'Male', value: 1 },
{ label: 'Female', value: 2 },
{ label: 'Neutral', value: 0 },
{ label: 'Unspecified', value: 9 },
],
}
}),
age: Property.Number({
displayName: 'Audience Age',
description: 'Helps adjust vocabulary and expressions to be age-appropriate.',
required: false,
}),
project_name: Property.ShortText({
displayName: 'Project Name',
description: 'A memorable name for your project to help organize tasks in your Camb.ai workspace.',
required: false,
}),
},
async run(context) {
const { auth } = context;
const { texts, source_language, target_language, formality, gender, age, project_name } = context.propsValue;
const payload: Record<string, unknown> = {
texts: texts.split('\n').filter(line => line.trim().length > 0),
source_language: Number(source_language),
target_language: Number(target_language),
};
if (formality !== undefined) payload['formality'] = formality;
if (gender !== undefined) payload['gender'] = gender;
if (age) payload['age'] = age;
if (project_name) payload['project_name'] = project_name;
const initialResponse = await httpClient.sendRequest<{ task_id: string }>({
method: HttpMethod.POST,
url: `${API_BASE_URL}/translate`,
headers: { 'x-api-key': auth.secret_text, 'Content-Type': 'application/json' },
body: payload,
});
const taskId = initialResponse.body.task_id;
let run_id: string | null = null;
let attempts = 0;
while (attempts < MAX_POLLING_ATTEMPTS) {
const statusResponse = await httpClient.sendRequest<{ status: string; run_id?: string }>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/translate/${taskId}`,
headers: { 'x-api-key': auth.secret_text },
});
if (statusResponse.body.status === 'SUCCESS') {
run_id = statusResponse.body.run_id ?? null;
break;
}
if (statusResponse.body.status === 'ERROR' || statusResponse.body.status === 'FAILED') {
throw new Error(`Translation task failed: ${JSON.stringify(statusResponse.body)}`);
}
await new Promise(resolve => setTimeout(resolve, POLLING_INTERVAL_MS));
attempts++;
}
if (!run_id) {
throw new Error("Translation task timed out or failed to return a task_id.");
}
const resultResponse = await httpClient.sendRequest<{ translations: string[] }>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/translation-result/${run_id}`,
headers: { 'x-api-key': auth.secret_text },
});
return resultResponse.body;
},
});

View File

@@ -0,0 +1,165 @@
import { Property } from "@activepieces/pieces-framework";
import { HttpMethod, httpClient } from "@activepieces/pieces-common";
import { cambaiAuth } from "../..";
export const API_BASE_URL = "https://client.camb.ai/apis";
export const POLLING_INTERVAL_MS = 5000;
export const LONG_POLLING_INTERVAL_MS = 10000;
export const MAX_POLLING_ATTEMPTS = 10;
export const LONG_MAX_POLLING_ATTEMPTS = 120;
type Voice = {
id: number;
voice_name: string;
};
type Folder = {
folder_id: number;
folder_name: string;
};
type Language = {
id: number;
language: string;
short_name: string;
};
export const listVoicesDropdown = Property.Dropdown({
auth: cambaiAuth,
displayName: 'Voice',
description: 'Select the voice to generate the speech.',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please authenticate first',
};
}
const response = await httpClient.sendRequest<Voice[]>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/list-voices`,
headers: {
'x-api-key': auth.secret_text,
},
});
const voices = response.body ?? [];
return {
disabled: false,
options: voices.map((voice) => ({
label: voice.voice_name,
value: voice.id,
})),
};
},
});
export const listSourceLanguagesDropdown = Property.Dropdown({
auth: cambaiAuth,
displayName: 'Source Language',
description: 'Select the original language of the input text.',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please authenticate first',
};
}
const response = await httpClient.sendRequest<Language[]>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/source-languages`,
headers: {
'x-api-key': auth.secret_text,
},
});
const languages = response.body ?? [];
return {
disabled: false,
options: languages.map((lang) => ({
label: `${lang.language} (${lang.short_name})`,
value: lang.id,
})),
};
},
});
export const listTargetLanguagesDropdown = Property.Dropdown({
displayName: 'Target Language',
description: 'Select the language to translate the text into.',
auth: cambaiAuth,
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please authenticate first',
};
}
const response = await httpClient.sendRequest<Language[]>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/target-languages`,
headers: {
'x-api-key': auth.secret_text,
},
});
const languages = response.body ?? [];
return {
disabled: false,
options: languages.map((lang) => ({
label: `${lang.language} (${lang.short_name})`,
value: lang.id,
})),
};
},
});
export const listFoldersDropdown = Property.Dropdown({
displayName: 'Folder',
auth: cambaiAuth,
description: 'Select the folder to save the task in.',
required: false,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
disabled: true,
options: [],
placeholder: 'Please authenticate first',
};
}
try {
const response = await httpClient.sendRequest<Folder[]>({
method: HttpMethod.GET,
url: `${API_BASE_URL}/folders`,
headers: {
'x-api-key': auth.secret_text,
},
});
const folders = response.body ?? [];
return {
disabled: false,
options: folders.map((folder) => ({
label: folder.folder_name,
value: folder.folder_id,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: "Could not load folders."
}
}
},
});

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"]
}