diff --git a/components/gandr/actions/convert-text-to-speech/convert-text-to-speech.mjs b/components/gandr/actions/convert-text-to-speech/convert-text-to-speech.mjs new file mode 100644 index 0000000000000..7ec4ca2672cbf --- /dev/null +++ b/components/gandr/actions/convert-text-to-speech/convert-text-to-speech.mjs @@ -0,0 +1,80 @@ +import fs from "fs"; +import stream from "stream"; +import { promisify } from "util"; +import { ConfigurationError } from "@pipedream/platform"; +import gandr from "../../gandr.app.mjs"; + +const MAX_INPUT_LENGTH = 2000; + +export default { + key: "gandr-convert-text-to-speech", + name: "Convert Text to Speech", + version: "0.0.1", + annotations: { + destructiveHint: false, + openWorldHint: true, + readOnlyHint: true, + }, + description: "Converts text into speech audio and saves the result to a file in the `/tmp` directory. Supports 23 languages, and every render is watermarked. [See the documentation](https://gandr.ai)", + type: "action", + props: { + gandr, + text: { + type: "string", + label: "Text", + description: `The text that will get converted into speech. Maximum ${MAX_INPUT_LENGTH} characters per request.`, + }, + voice: { + propDefinition: [ + gandr, + "voice", + ], + default: "gandr-mia", + }, + responseFormat: { + propDefinition: [ + gandr, + "responseFormat", + ], + optional: true, + }, + syncDir: { + type: "dir", + accessMode: "write", + sync: true, + }, + }, + async run({ $ }) { + const { + gandr, + text, + voice, + } = this; + + if (text.length > MAX_INPUT_LENGTH) { + throw new ConfigurationError(`Text is ${text.length} characters. The maximum is ${MAX_INPUT_LENGTH} characters per request. Split longer text into multiple requests.`); + } + + const responseFormat = this.responseFormat || "mp3"; + + const { data: response } = await gandr.createSpeech({ + $, + data: { + model: "tts-1", + input: text, + voice, + response_format: responseFormat, + }, + }); + + const filePath = `/tmp/gandr-speech-${Date.now()}.${responseFormat}`; + + const pipeline = promisify(stream.pipeline); + await pipeline(response, fs.createWriteStream(filePath)); + + $.export("$summary", `Generated speech audio with voice ${voice} and saved it to ${filePath}`); + return { + filePath, + }; + }, +}; diff --git a/components/gandr/gandr.app.mjs b/components/gandr/gandr.app.mjs new file mode 100644 index 0000000000000..5214bfca072d3 --- /dev/null +++ b/components/gandr/gandr.app.mjs @@ -0,0 +1,63 @@ +import { axios } from "@pipedream/platform"; + +export default { + type: "app", + app: "gandr", + propDefinitions: { + voice: { + type: "string", + label: "Voice", + description: "The voice that will be used for the generated speech.", + options: [ + "gandr-mia", + "gandr-ava", + "gandr-jenny", + "gandr-dane", + "gandr-leo", + "gandr-lewis", + ], + }, + responseFormat: { + type: "string", + label: "Response Format", + description: "The audio format of the response. `pcm` is headerless signed 16-bit little-endian mono audio at 24000 Hz. Default: `mp3`", + options: [ + "mp3", + "wav", + "pcm", + ], + default: "mp3", + }, + }, + methods: { + _apiUrl() { + return "https://tts.gandr.ai/v1"; + }, + _getHeaders(args = {}) { + return { + "Authorization": `Bearer ${this.$auth.api_key}`, + ...args, + }; + }, + async _makeRequest({ + $ = this, path, headers, ...opts + }) { + const config = { + url: `${this._apiUrl()}/${path}`, + headers: this._getHeaders(headers), + ...opts, + }; + + return axios($, config); + }, + createSpeech(args = {}) { + return this._makeRequest({ + method: "POST", + path: "audio/speech", + returnFullResponse: true, + responseType: "stream", + ...args, + }); + }, + }, +}; diff --git a/components/gandr/package.json b/components/gandr/package.json new file mode 100644 index 0000000000000..319da04eb5cb8 --- /dev/null +++ b/components/gandr/package.json @@ -0,0 +1,18 @@ +{ + "name": "@pipedream/gandr", + "version": "0.1.0", + "description": "Pipedream Gandr Components", + "main": "gandr.app.mjs", + "keywords": [ + "pipedream", + "gandr" + ], + "homepage": "https://pipedream.com/apps/gandr", + "author": "Pipedream (https://pipedream.com/)", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.4.0" + } +}