-
Notifications
You must be signed in to change notification settings - Fork 5.8k
New Components - gandr #21830
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
New Components - gandr #21830
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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)", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Expand the action description for agent use. Include the 2,000-character limit, supported voice and response formats, output-file behavior, and relevant gotchas. The current description does not explain when to use the action or how to provide its key parameters. As per path instructions, action descriptions must include purpose, parameter guidance, gotchas, and documentation. 🤖 Prompt for AI AgentsSource: Path instructions |
||
| 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}`; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Write the file under the configured stash directory. When Based on learnings, file-output actions in this repository use 🤖 Prompt for AI AgentsSource: Learnings 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- scoped guidance ---'
cat .github/pipedream-action-guidelines.md
printf '%s\n' '--- action outline ---'
ast-grep outline components/gandr/actions/convert-text-to-speech/convert-text-to-speech.mjs
printf '%s\n' '--- action source ---'
cat -n components/gandr/actions/convert-text-to-speech/convert-text-to-speech.mjs
printf '%s\n' '--- related responseFormat and syncDir references ---'
rg -n -C 3 'responseFormat|syncDir|createWriteStream|filePath' components/gandr components/donately .github/pipedream-component-guidelines.md .github/pipedream-action-guidelines.mdRepository: PipedreamHQ/pipedream Length of output: 22186 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- Gandr app responseFormat definition ---'
cat -n components/gandr/gandr.app.mjs | sed -n '1,80p'
printf '%s\n' '--- responseFormat option declarations and runner references ---'
rg -n -C 4 'responseFormat|options|propDefinition|agent|MCP|validate' components/gandr .github | head -240
printf '%s\n' '--- path normalization probe ---'
node - <<'JS'
const path = require("path");
const formats = ["../../target", "../../../target", "../../../../target", "mp3"];
for (const format of formats) {
const raw = `/tmp/gandr-speech-123.${format}`;
console.log(JSON.stringify({ format, raw, normalized: path.normalize(raw) }));
}
JSRepository: PipedreamHQ/pipedream Length of output: 21833 🌐 Web query:
💡 Result: In Pipedream, component props are configured using a combination of static definitions and dynamic options [1][2]. When a component prop defines an options property, it can be provided as an array of values or a dynamic method (async function) that fetches options from an API [1][2]. For external integrations—including when using Model Context Protocol (MCP) or the Pipedream Connect API—the CONFIGURE_COMPONENT tool is used to retrieve valid options for a specific prop [3][4]. This tool requires the componentKey and the propName to function [4]. Regarding values outside of defined options: 1. Dynamic Configuration: Many Pipedream components are designed to be dynamic. If a prop requires specific values, the API or MCP tool will return the available set [5]. 2. Custom Expressions: When a prop is not strictly limited to a predefined list (or when a user needs to provide a dynamic reference), Pipedream supports custom expressions [3]. In many UI and API contexts, if a user provides a value that is not in the fetched options list, the platform may treat it as a raw string or custom expression, depending on the component's underlying implementation [5][3]. 3. Prop Configuration via API: When integrating via API (e.g., configuring a component via Pipedream Connect), you interact with the CONFIGURE_COMPONENT endpoint [6][5][7]. If you are setting a value that is dynamic or outside the "standard" list, ensure the payload adheres to the expected structure (such as the { lv: { label, value } } format if the prop requires explicit label-value pairs for remote options) [8][7]. If you are encountering issues where a value outside the options is rejected, verify if the component prop definition has enforced strict validation or if it requires the lv (label-value) wrapper to maintain compatibility with the UI's expected format [8]. Citations:
Validate The 🤖 Prompt for AI Agents |
||
|
|
||
| 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, | ||
| }; | ||
| }, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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.", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Document the allowed
As per path instructions, descriptions for non-obvious IDs must include concrete valid values or examples. 🤖 Prompt for AI AgentsSource: Path instructions |
||
| 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, | ||
| }); | ||
| }, | ||
| }, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <support@pipedream.com> (https://pipedream.com/)", | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "dependencies": { | ||
| "@pipedream/platform": "^3.4.0" | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
Set
readOnlyHinttofalse.This action calls a speech-generation endpoint and writes an audio file. It does not exclusively read data. Set
readOnlyHint: falseso agent safety metadata matches the action.As per path instructions, the TTS action must use
readOnlyHint: false,destructiveHint: false, andopenWorldHint: true.🤖 Prompt for AI Agents
Source: Path instructions