From c7225defcfc24eb16e8c0d1b2edb7f6b95e5dadd Mon Sep 17 00:00:00 2001 From: Jorge Cortes Date: Thu, 10 Apr 2025 16:46:13 -0500 Subject: [PATCH] [Components] speak_ai - new components --- .../actions/analyze-text/analyze-text.mjs | 42 ++ .../get-transcription/get-transcription.mjs | 41 ++ .../actions/upload-media/upload-media.mjs | 82 ++++ components/speak_ai/common/constants.mjs | 13 + components/speak_ai/package.json | 7 +- components/speak_ai/sources/common/events.mjs | 18 + .../speak_ai/sources/common/webhook.mjs | 87 +++++ .../new-media-created-instant.mjs | 35 ++ .../new-media-created-instant/test-event.mjs | 365 ++++++++++++++++++ .../new-text-analyzed-instant.mjs | 34 ++ .../new-text-analyzed-instant/test-event.mjs | 87 +++++ components/speak_ai/speak_ai.app.mjs | 124 +++++- pnpm-lock.yaml | 17 +- 13 files changed, 937 insertions(+), 15 deletions(-) create mode 100644 components/speak_ai/actions/analyze-text/analyze-text.mjs create mode 100644 components/speak_ai/actions/get-transcription/get-transcription.mjs create mode 100644 components/speak_ai/actions/upload-media/upload-media.mjs create mode 100644 components/speak_ai/common/constants.mjs create mode 100644 components/speak_ai/sources/common/events.mjs create mode 100644 components/speak_ai/sources/common/webhook.mjs create mode 100644 components/speak_ai/sources/new-media-created-instant/new-media-created-instant.mjs create mode 100644 components/speak_ai/sources/new-media-created-instant/test-event.mjs create mode 100644 components/speak_ai/sources/new-text-analyzed-instant/new-text-analyzed-instant.mjs create mode 100644 components/speak_ai/sources/new-text-analyzed-instant/test-event.mjs diff --git a/components/speak_ai/actions/analyze-text/analyze-text.mjs b/components/speak_ai/actions/analyze-text/analyze-text.mjs new file mode 100644 index 0000000000000..1452278e3c11d --- /dev/null +++ b/components/speak_ai/actions/analyze-text/analyze-text.mjs @@ -0,0 +1,42 @@ +import app from "../../speak_ai.app.mjs"; + +export default { + key: "speak_ai-analyze-text", + name: "Analyze Text", + description: "Analyzes a block of text for key insights, sentiment, and keyword extraction using Speak Ai's NLP engine. [See the documentation](https://docs.speakai.co/#d65573c9-98ad-4089-93ad-9d0a173fdeea).", + version: "0.0.1", + type: "action", + props: { + app, + folderId: { + propDefinition: [ + app, + "folderId", + ], + }, + mediaId: { + propDefinition: [ + app, + "mediaId", + ({ folderId }) => ({ + folderId, + mediaType: "text", + }), + ], + }, + }, + async run({ $ }) { + const { + app, + mediaId, + } = this; + + const response = await app.getTextInsight({ + $, + mediaId, + }); + + $.export("$summary", `Successfully analyzed text with ID \`${response.data.mediaId}\`.`); + return response; + }, +}; diff --git a/components/speak_ai/actions/get-transcription/get-transcription.mjs b/components/speak_ai/actions/get-transcription/get-transcription.mjs new file mode 100644 index 0000000000000..6992d4c3e0dc9 --- /dev/null +++ b/components/speak_ai/actions/get-transcription/get-transcription.mjs @@ -0,0 +1,41 @@ +import app from "../../speak_ai.app.mjs"; + +export default { + key: "speak_ai-get-transcription", + name: "Get Transcription", + description: "Retrieve the full transcription of a processed media file. [See the documentation](https://docs.speakai.co/#0b586e5b-6e0a-4b79-b440-e6889a803ccd).", + version: "0.0.1", + type: "action", + props: { + app, + folderId: { + propDefinition: [ + app, + "folderId", + ], + }, + mediaId: { + propDefinition: [ + app, + "mediaId", + ({ folderId }) => ({ + folderId, + }), + ], + }, + }, + async run({ $ }) { + const { + app, + mediaId, + } = this; + + const response = await app.getInsight({ + $, + mediaId, + }); + + $.export("$summary", `Successfully retrieved transcription for media ID \`${response.data.mediaId}\`.`); + return response.data.insight.transcript; + }, +}; diff --git a/components/speak_ai/actions/upload-media/upload-media.mjs b/components/speak_ai/actions/upload-media/upload-media.mjs new file mode 100644 index 0000000000000..c80646b5d391f --- /dev/null +++ b/components/speak_ai/actions/upload-media/upload-media.mjs @@ -0,0 +1,82 @@ +import app from "../../speak_ai.app.mjs"; + +export default { + key: "speak_ai-upload-media", + name: "Upload Media", + description: "Upload an audio or video file for transcription and natural language processing into Speak AI. [See the documentation](https://docs.speakai.co/#c6106a66-6a3d-4b05-b4a2-4a68a4c1e95d).", + version: "0.0.1", + type: "action", + props: { + app, + name: { + type: "string", + label: "Name", + description: "Name of the media file", + }, + url: { + type: "string", + label: "URL", + description: "Public URL or AWS signed URL", + }, + mediaType: { + propDefinition: [ + app, + "mediaType", + ], + }, + folderId: { + propDefinition: [ + app, + "folderId", + ], + }, + description: { + type: "string", + label: "Description", + description: "Description of the media file", + optional: true, + }, + tags: { + type: "string[]", + label: "Tags", + description: "Optional metadata tags for the media file upload", + optional: true, + }, + }, + methods: { + uploadMedia(args = {}) { + return this.app.post({ + path: "/media/upload", + ...args, + }); + }, + }, + async run({ $ }) { + const { + uploadMedia, + name, + url, + mediaType, + folderId, + description, + tags, + } = this; + + const response = await uploadMedia({ + $, + data: { + name, + url, + mediaType, + folderId, + description, + tags: Array.isArray(tags) + ? tags.join(",") + : tags, + }, + }); + + $.export("$summary", `Successfully uploaded media with ID \`${response.data.mediaId}\`.`); + return response; + }, +}; diff --git a/components/speak_ai/common/constants.mjs b/components/speak_ai/common/constants.mjs new file mode 100644 index 0000000000000..9329ee12a078f --- /dev/null +++ b/components/speak_ai/common/constants.mjs @@ -0,0 +1,13 @@ +const BASE_URL = "https://api.speakai.co"; +const VERSION_PATH = "/v1"; + +const DEFAULT_LIMIT = 50; + +const WEBHOOK_ID = "webhookId"; + +export default { + BASE_URL, + VERSION_PATH, + DEFAULT_LIMIT, + WEBHOOK_ID, +}; diff --git a/components/speak_ai/package.json b/components/speak_ai/package.json index 41469f79ac119..cca702f52a789 100644 --- a/components/speak_ai/package.json +++ b/components/speak_ai/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/speak_ai", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Speak AI Components", "main": "speak_ai.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3" } -} \ No newline at end of file +} diff --git a/components/speak_ai/sources/common/events.mjs b/components/speak_ai/sources/common/events.mjs new file mode 100644 index 0000000000000..3379253f457e2 --- /dev/null +++ b/components/speak_ai/sources/common/events.mjs @@ -0,0 +1,18 @@ +export default { + MEDIA_CREATED: "media.created", + MEDIA_ANALYZED: "media.analyzed", + MEDIA_REANALYZED: "media.reanalyzed", + MEDIA_FAILED: "media.failed", + TEXT_CREATED: "text.created", + TEXT_ANALYZED: "text.analyzed", + TEXT_REANALYZED: "text.reanalyzed", + TEXT_FAILED: "text.failed", + TEXT_DELETED: "text.deleted", + EMBED_RECORDER_CREATED: "embed_recorder.created", + EMBED_RECORDER_DELETED: "embed_recorder.deleted", + EMBED_RECORDER_RECORDING_RECEIVED: "embed_recorder.recording_received", + MEETING_ASSISTANT_STATUS: "meeting_assistant.status", + CHAT_STATUS: "chat.status", + CSV_UPLOADED: "csv.uploaded", + CSV_FAILED: "csv.failed", +}; diff --git a/components/speak_ai/sources/common/webhook.mjs b/components/speak_ai/sources/common/webhook.mjs new file mode 100644 index 0000000000000..e84876781925d --- /dev/null +++ b/components/speak_ai/sources/common/webhook.mjs @@ -0,0 +1,87 @@ +import { ConfigurationError } from "@pipedream/platform"; +import app from "../../speak_ai.app.mjs"; +import constants from "../../common/constants.mjs"; + +export default { + props: { + app, + db: "$.service.db", + http: "$.interface.http", + }, + hooks: { + async activate() { + const { + http: { endpoint: callbackUrl }, + createWebhook, + getEvents, + setWebhookId, + } = this; + + const response = + await createWebhook({ + data: { + callbackUrl, + events: getEvents(), + }, + }); + + setWebhookId(response.data.webhookId); + }, + async deactivate() { + const { + deleteWebhook, + getWebhookId, + } = this; + + const webhookId = getWebhookId(); + if (webhookId) { + await deleteWebhook({ + webhookId, + }); + } + }, + }, + methods: { + generateMeta() { + throw new ConfigurationError("generateMeta is not implemented"); + }, + setWebhookId(value) { + this.db.set(constants.WEBHOOK_ID, value); + }, + getWebhookId() { + return this.db.get(constants.WEBHOOK_ID); + }, + getEvents() { + throw new ConfigurationError("getEvents is not implemented"); + }, + async getData(resource) { + return resource; + }, + async processResource(resource) { + const data = await this.getData(resource); + this.$emit({ + ...resource, + data, + }, this.generateMeta(resource)); + }, + createWebhook(args = {}) { + return this.app.post({ + debug: true, + path: "/webhook", + ...args, + }); + }, + deleteWebhook({ + webhookId, ...args + } = {}) { + return this.app.delete({ + debug: true, + path: `/webhook/${webhookId}`, + ...args, + }); + }, + }, + async run({ body }) { + await this.processResource(body); + }, +}; diff --git a/components/speak_ai/sources/new-media-created-instant/new-media-created-instant.mjs b/components/speak_ai/sources/new-media-created-instant/new-media-created-instant.mjs new file mode 100644 index 0000000000000..e4651cdb6214a --- /dev/null +++ b/components/speak_ai/sources/new-media-created-instant/new-media-created-instant.mjs @@ -0,0 +1,35 @@ +import common from "../common/webhook.mjs"; +import events from "../common/events.mjs"; +import sampleEmit from "./test-event.mjs"; + +export default { + ...common, + key: "speak_ai-new-media-created-instant", + name: "New Media Created (Instant)", + description: "Emit new event when a new media file is created. Useful for initiating workflows based on new media intake. [See the documentation](https://docs.speakai.co/#5777a89c-a6c3-4d0e-aab1-d33fdec5cbe8).", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEvents() { + return [ + events.MEDIA_CREATED, + ]; + }, + async getData(resource) { + const { data } = await this.app.getInsight({ + mediaId: resource.mediaId, + }); + return data; + }, + generateMeta(resource) { + return { + id: resource.mediaId, + summary: `New Media Created: ${resource.mediaId}`, + ts: Date.now(), + }; + }, + }, + sampleEmit, +}; diff --git a/components/speak_ai/sources/new-media-created-instant/test-event.mjs b/components/speak_ai/sources/new-media-created-instant/test-event.mjs new file mode 100644 index 0000000000000..7c27eafeb95b7 --- /dev/null +++ b/components/speak_ai/sources/new-media-created-instant/test-event.mjs @@ -0,0 +1,365 @@ +export default { + "eventType": "media.created", + "state": "uploaded", + "mediaId": "f2a7bafae402", + "folderId": "2b686b1415cb", + "data": { + "_id": "67f83a55b18061d69ce74d63", + "companyId": "67f483868f6e5607210167c4", + "userId": "67f483868f6e5607210167dc", + "folderId": "2b686b1415cb", + "mediaType": "audio", + "name": "Test 6", + "description": "", + "tags": [], + "sourceUrl": "https://archive.org/download/testmp3testfile/mpthreetest.mp3", + "processingProgress": "99", + "uploadType": "api", + "state": "preparingAnalysis", + "sourceLanguage": "en-US", + "insight": { + "transcript": [ + { + "id": 1, + "speakerId": "0", + "confidence": 0.79, + "text": "Okay. We are trying this for a second time to test the ability to upload an mp3 file. Hopefully this will work.", + "entities": [ + { + "id": 1, + "speakerId": "0", + "confidence": 0.78543806, + "text": "Okay.", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 0.64, + "endInSec": 1.04 + } + }, + { + "id": 2, + "speakerId": "0", + "confidence": 0.9873417, + "text": "We", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 1.04, + "endInSec": 1.1999999 + } + }, + { + "id": 3, + "speakerId": "0", + "confidence": 0.83697766, + "text": "are", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 1.1999999, + "endInSec": 1.36 + } + }, + { + "id": 4, + "speakerId": "0", + "confidence": 0.9977418, + "text": "trying", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 1.36, + "endInSec": 1.68 + } + }, + { + "id": 5, + "speakerId": "0", + "confidence": 0.9943204, + "text": "this", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 1.68, + "endInSec": 1.8399999 + } + }, + { + "id": 6, + "speakerId": "0", + "confidence": 0.9661982, + "text": "for", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 1.8399999, + "endInSec": 2.1599998 + } + }, + { + "id": 7, + "speakerId": "0", + "confidence": 0.98577476, + "text": "a", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 2.1599998, + "endInSec": 2.32 + } + }, + { + "id": 8, + "speakerId": "0", + "confidence": 0.9993876, + "text": "second", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 2.32, + "endInSec": 2.8 + } + }, + { + "id": 9, + "speakerId": "0", + "confidence": 0.999137, + "text": "time", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 2.8, + "endInSec": 3.3 + } + }, + { + "id": 10, + "speakerId": "0", + "confidence": 0.9778196, + "text": "to", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 3.36, + "endInSec": 3.6 + } + }, + { + "id": 11, + "speakerId": "0", + "confidence": 0.99778783, + "text": "test", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 3.6, + "endInSec": 4.1 + } + }, + { + "id": 12, + "speakerId": "0", + "confidence": 0.99737227, + "text": "the", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 4.4, + "endInSec": 4.64 + } + }, + { + "id": 13, + "speakerId": "0", + "confidence": 0.9994412, + "text": "ability", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 4.64, + "endInSec": 5.14 + } + }, + { + "id": 14, + "speakerId": "0", + "confidence": 0.99633527, + "text": "to", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 5.68, + "endInSec": 6.18 + } + }, + { + "id": 15, + "speakerId": "0", + "confidence": 0.9933255, + "text": "upload", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 6.72, + "endInSec": 7.22 + } + }, + { + "id": 16, + "speakerId": "0", + "confidence": 0.9071132, + "text": "an", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 7.3599997, + "endInSec": 7.8599997 + } + }, + { + "id": 17, + "speakerId": "0", + "confidence": 0.89895034, + "text": "mp3", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 7.9199996, + "endInSec": 8.42 + } + }, + { + "id": 18, + "speakerId": "0", + "confidence": 0.98591423, + "text": "file.", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 8.88, + "endInSec": 9.38 + } + }, + { + "id": 19, + "speakerId": "0", + "confidence": 0.9933862, + "text": "Hopefully", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 10.08, + "endInSec": 10.48 + } + }, + { + "id": 20, + "speakerId": "0", + "confidence": 0.5602547, + "text": "this", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 10.48, + "endInSec": 10.719999 + } + }, + { + "id": 21, + "speakerId": "0", + "confidence": 0.9933391, + "text": "will", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 10.719999, + "endInSec": 10.88 + } + }, + { + "id": 22, + "speakerId": "0", + "confidence": 0.97382975, + "text": "work.", + "language": "en-US", + "speaker_confidence": 1, + "instances": { + "startInSec": 10.88, + "endInSec": 11.38 + } + } + ], + "language": "en-US", + "instances": [ + { + "start": "00:00:00.640", + "end": "00:00:11.380", + "startInSec": 0.64, + "endInSec": 11.38 + } + ] + } + ], + "speakers": [ + { + "id": 0, + "name": "0", + "instances": [ + { + "start": "00:00:00.640", + "end": "00:00:11.380", + "startInSec": 0.64, + "endInSec": 11.38 + } + ], + "totalWords": 22, + "duration": 11, + "wpm": 120 + } + ], + "arts": [], + "brands": [], + "cardinals": [], + "dates": [], + "events": [], + "geopolitical": [], + "keywords": [], + "languages": [], + "laws": [], + "locations": [], + "money": [], + "nationalities": [], + "ordinals": [], + "people": [], + "percentages": [], + "products": [], + "quantities": [], + "times": [], + "addresses": [] + }, + "duration": { + "inSecond": 12.416125, + "end": "00:00:11.380", + "start": "00:00:00.640" + }, + "assignTo": "", + "remark": "", + "text": "", + "rawText": "", + "count": { + "wordCount": 0, + "characterCount": 0, + "characterCountWithoutSpace": 0 + }, + "createdAt": "2025-04-10T21:38:29.310Z", + "mediaId": "f2a7bafae402", + "sentiment": [], + "fields": [], + "updatedAt": "2025-04-10T21:38:29.465Z", + "originalCreatedAt": "2025-04-10T21:38:29.465Z", + "publishedUrl": "media/67f483868f6e5607210167dc/audio/1744321111530-f2a7bafae402-test_6.mp3", + "mediaUrl": "https://d2ekbs8cbzdc9j.cloudfront.net/media/67f483868f6e5607210167dc/audio/1744321111530-f2a7bafae402-test_6.mp3?Expires=1744331915&Key-Pair-Id=APKAVV6KHDL4AR2PFC6W&Signature=onLD1YIHz9bd0MM5F50Zt~fBouf6YfEGE-ZThUYequhyJZJvo6JfhJmtTf3UnqlAR~KSB5ZJJCVKmGQjOjFi5TZHSuu8aJ5xBK4ueO3r16MIZv2nqLo9WIbCQbTkGXGv3mwYb3nnszZSH1ZH94DgEA5-tBr~34CzPJ0ld0KTu6CRig78SzErU2GffF1ovoub~0XbmxKXWKsqeGIoxS5znbGRfCl1-1tZXOHHGgSAaLwANn65Ay4LjzlYocjRSWP8VPLlnFRbTBIJrI7B8U1J0sW2etxFJZG4VGt-ZpIClhKYPLTQ~M8RozFreL5eGGe68mCWBKzu~WKMhTCnKQyF8Q__", + "downloadUrl": "https://d2ekbs8cbzdc9j.cloudfront.net/media/67f483868f6e5607210167dc/audio/1744321111530-f2a7bafae402-test_6.mp3?Expires=1744331915&Key-Pair-Id=APKAVV6KHDL4AR2PFC6W&Signature=onLD1YIHz9bd0MM5F50Zt~fBouf6YfEGE-ZThUYequhyJZJvo6JfhJmtTf3UnqlAR~KSB5ZJJCVKmGQjOjFi5TZHSuu8aJ5xBK4ueO3r16MIZv2nqLo9WIbCQbTkGXGv3mwYb3nnszZSH1ZH94DgEA5-tBr~34CzPJ0ld0KTu6CRig78SzErU2GffF1ovoub~0XbmxKXWKsqeGIoxS5znbGRfCl1-1tZXOHHGgSAaLwANn65Ay4LjzlYocjRSWP8VPLlnFRbTBIJrI7B8U1J0sW2etxFJZG4VGt-ZpIClhKYPLTQ~M8RozFreL5eGGe68mCWBKzu~WKMhTCnKQyF8Q__" + } +}; diff --git a/components/speak_ai/sources/new-text-analyzed-instant/new-text-analyzed-instant.mjs b/components/speak_ai/sources/new-text-analyzed-instant/new-text-analyzed-instant.mjs new file mode 100644 index 0000000000000..daf0d7c36026e --- /dev/null +++ b/components/speak_ai/sources/new-text-analyzed-instant/new-text-analyzed-instant.mjs @@ -0,0 +1,34 @@ +import common from "../common/webhook.mjs"; +import events from "../common/events.mjs"; + +export default { + ...common, + key: "speak_ai-new-text-analyzed-instant", + name: "New Text Analyzed (Instant)", + description: "Emit new event when a new text is analyzed. Useful for initiating workflows based on new text analysis. [See the documentation](https://docs.speakai.co/#5777a89c-a6c3-4d0e-aab1-d33fdec5cbe8).", + version: "0.0.1", + type: "source", + dedupe: "unique", + methods: { + ...common.methods, + getEvents() { + return [ + events.TEXT_ANALYZED, + events.TEXT_REANALYZED, + ]; + }, + async getData(resource) { + const { data } = await this.app.getTextInsight({ + mediaId: resource.mediaId, + }); + return data; + }, + generateMeta(resource) { + return { + id: resource.mediaId, + summary: `New Text Analyzed: ${resource.mediaId}`, + ts: Date.now(), + }; + }, + }, +}; diff --git a/components/speak_ai/sources/new-text-analyzed-instant/test-event.mjs b/components/speak_ai/sources/new-text-analyzed-instant/test-event.mjs new file mode 100644 index 0000000000000..29572bebcc3eb --- /dev/null +++ b/components/speak_ai/sources/new-text-analyzed-instant/test-event.mjs @@ -0,0 +1,87 @@ +export default { + "eventType": "text.analyzed", + "state": "uploaded", + "mediaId": "13a672e5b22c", + "data": { + "folderId": "2b686b1415cb", + "name": "New Note - 10-04-2025 16:42:27", + "description": "", + "tags": [], + "state": "processed", + "sourceLanguage": "en-US", + "insight": { + "transcript": [], + "speakers": [], + "arts": [], + "brands": [], + "cardinals": [], + "dates": [], + "events": [], + "geopolitical": [], + "keywords": [ + { + "id": 0, + "name": "Quick test", + "isCustom": true, + "isDeleted": false, + "instances": [ + { + "endChar": 20, + "startChar": 10 + } + ] + } + ], + "languages": [], + "laws": [], + "locations": [], + "money": [], + "nationalities": [], + "ordinals": [], + "people": [], + "percentages": [], + "products": [], + "quantities": [], + "times": [], + "topics": [], + "addresses": [] + }, + "assignTo": "", + "remark": "", + "text": "

This is a quick test!

", + "rawText": "This is a quick test!", + "count": { + "characterCountWithoutSpace": 0, + "wordCount": 5, + "characterCount": 21 + }, + "createdAt": "2025-04-10T21:42:28.042Z", + "mediaId": "13a672e5b22c", + "sentiment": [ + { + "document": { + "Compound": 0, + "Negative": 0, + "Neutral": 100, + "Positive": 0 + }, + "sentences": [ + { + "id": 1, + "instances": [], + "score": { + "compound": 0, + "neg": 0, + "neu": 1, + "pos": 0 + }, + "text": "This is a quick test! " + } + ] + } + ], + "fields": [], + "updatedAt": "2025-04-10T21:43:31.721Z", + "originalCreatedAt": "2025-04-10T21:42:28.190Z" + } +}; diff --git a/components/speak_ai/speak_ai.app.mjs b/components/speak_ai/speak_ai.app.mjs index 9d1e6797d11e0..65b30467db45b 100644 --- a/components/speak_ai/speak_ai.app.mjs +++ b/components/speak_ai/speak_ai.app.mjs @@ -1,11 +1,127 @@ +import { axios } from "@pipedream/platform"; +import constants from "./common/constants.mjs"; + export default { type: "app", app: "speak_ai", - propDefinitions: {}, + propDefinitions: { + folderId: { + type: "string", + label: "Folder ID", + description: "The ID of the folder to upload or retrieve files from", + async options({ page }) { + const { data: { folders } } = await this.listFolders({ + params: { + page, + pageSize: constants.DEFAULT_LIMIT, + }, + }); + return folders.map(({ + folderId: value, + name: label, + }) => ({ + label, + value, + })); + }, + }, + mediaType: { + type: "string", + label: "Media Type", + description: "Type of media file (audio or video)", + options: [ + "audio", + "video", + ], + }, + mediaId: { + type: "string", + label: "Media ID", + description: "The ID of the media file to retrieve the full transcription for", + async options({ + page, folderId, mediaType, + }) { + const { data: { mediaList } } = await this.listMedia({ + params: { + page, + pageSize: constants.DEFAULT_LIMIT, + folderId, + mediaType, + }, + }); + return mediaList.map(({ + mediaId: value, + name: label, + }) => ({ + label, + value, + })); + }, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + getUrl(path) { + return `${constants.BASE_URL}${constants.VERSION_PATH}${path}`; + }, + getHeaders(headers) { + const { + api_key: apiKey, + oauth_access_token: accessToken, + } = this.$auth; + return { + ...headers, + "x-speakai-key": apiKey, + "x-access-token": accessToken, + }; + }, + _makeRequest({ + $ = this, path, headers, ...args + } = {}) { + return axios($, { + ...args, + url: this.getUrl(path), + headers: this.getHeaders(headers), + }); + }, + post(args = {}) { + return this._makeRequest({ + method: "post", + ...args, + }); + }, + delete(args = {}) { + return this._makeRequest({ + method: "delete", + ...args, + }); + }, + listFolders(args = {}) { + return this._makeRequest({ + path: "/folder", + ...args, + }); + }, + listMedia(args = {}) { + return this._makeRequest({ + path: "/media", + ...args, + }); + }, + getInsight({ + mediaId, ...args + } = {}) { + return this._makeRequest({ + path: `/media/insight/${mediaId}`, + ...args, + }); + }, + getTextInsight({ + mediaId, ...args + } = {}) { + return this._makeRequest({ + path: `/text/insight/${mediaId}`, + ...args, + }); }, }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a1a4bb091b81..c59ee154a3aad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4308,8 +4308,7 @@ importers: components/facebook_conversions: {} - components/facebook_graph_api: - specifiers: {} + components/facebook_graph_api: {} components/facebook_groups: dependencies: @@ -4929,8 +4928,7 @@ importers: components/gatekeeper: {} - components/gather: - specifiers: {} + components/gather: {} components/gatherup: dependencies: @@ -11991,8 +11989,7 @@ importers: components/smartengage: {} - components/smartlead: - specifiers: {} + components/smartlead: {} components/smartproxy: {} @@ -12221,7 +12218,11 @@ importers: components/sparkpost: {} - components/speak_ai: {} + components/speak_ai: + dependencies: + '@pipedream/platform': + specifier: ^3.0.3 + version: 3.0.3 components/specific: dependencies: @@ -34509,8 +34510,6 @@ snapshots: '@putout/operator-filesystem': 5.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3)) '@putout/operator-json': 2.2.0 putout: 36.13.1(eslint@8.57.1)(typescript@5.6.3) - transitivePeerDependencies: - - supports-color '@putout/operator-regexp@1.0.0(putout@36.13.1(eslint@8.57.1)(typescript@5.6.3))': dependencies: