Created
August 15, 2019 11:05
-
-
Save pgilad/75d8ccc689f52565ae00581ba7c4d07b to your computer and use it in GitHub Desktop.
AWS Lambda PolyTalk Slack Integration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const querystring = require('querystring'); | |
const request = require('request-promise-native'); | |
// You must bundle the latest version of the AWS JS SDK (2.7.9) | |
// The built-in SDK version does not know about the Polly text-to-speech service. | |
const AWS = require('aws-sdk'); | |
const SLACK_TOKEN = process.env.SLACK_TOKEN; | |
const SLACK_UPLOAD_URI = 'https://slack.com/api/files.upload'; | |
const AUDIO_FILENAME = 'audio.mp3'; | |
const MAX_ALLOWED_TEXT_LENGTH = 140; | |
// This defaults to the region the Lambda function is in. | |
// Note that Polly is not available in all regions yet. | |
AWS.config.update({ | |
region: process.env.AWS_DEFAULT_REGION | |
}); | |
const getSpeech = text => { | |
const Polly = new AWS.Polly({ | |
signatureVersion: 'v4', | |
region: 'eu-west-1' | |
}); | |
const params = { | |
Text: text, | |
OutputFormat: 'mp3', | |
TextType: 'text', | |
VoiceId: process.env.AWS_POLLY_VOICE_ID || 'Emma', | |
}; | |
return new Promise((resolve, reject) => { | |
Polly.synthesizeSpeech(params, (err, data) => { | |
if (err) { | |
return reject(err); | |
} | |
resolve(data); | |
}); | |
}); | |
}; | |
const uploadFileToSlack = (channelId, audio) => { | |
const formData = { | |
token: SLACK_TOKEN, | |
channels: channelId, | |
filename: AUDIO_FILENAME, | |
title: 'Audio Recording', | |
file: { | |
value: Buffer.from(audio.AudioStream, 'binary'), | |
options: { | |
filename: AUDIO_FILENAME, | |
contentType: 'audio/mpeg', | |
} | |
} | |
}; | |
const options = { | |
url: SLACK_UPLOAD_URI, | |
method: 'post', | |
formData, | |
}; | |
return request(options); | |
}; | |
const respondWithError = (text, callback) => callback(null, {response_type: 'ephemeral', text}); | |
exports.handler = async (event, context, callback) => { | |
const parsed = querystring.parse(event.body); | |
/** @namespace parsed.channel_id */ | |
const channelId = parsed.channel_id; | |
const textToSpeak = parsed.text; | |
console.log('Got the following event: ', parsed); | |
if (!textToSpeak) { | |
console.error('Got empty text'); | |
return respondWithError('No text to convert', callback); | |
} | |
if (textToSpeak === undefined || (textToSpeak.length > MAX_ALLOWED_TEXT_LENGTH)) { | |
console.error(`Client tried to convert text with length ${textToSpeak.length}`); | |
return respondWithError(`Text limited to max of ${MAX_ALLOWED_TEXT_LENGTH} characters`, callback); | |
} | |
console.log(`Converting text "${textToSpeak}"`); | |
const audio = await getSpeech(textToSpeak); | |
if (!(audio.AudioStream instanceof Buffer)) { | |
return respondWithError('Could not synthesize audio', callback); | |
} | |
console.log('Successfully used Polly to convert to Buffer'); | |
console.log(`Uploading file to slack channel: ${channelId}`); | |
let response; | |
try { | |
response = await uploadFileToSlack(channelId, audio); | |
// the response returns | |
response = JSON.parse(response); | |
} catch (e) { | |
console.error('Could not upload audio file', e); | |
return respondWithError('Successfully converted text to audio, but failed to upload to Slack', callback); | |
} | |
if (!response || response.ok !== true) { | |
console.error('Problem in uploading file', response); | |
return respondWithError('Successfully converted text to audio, but failed to upload to Slack', callback); | |
} | |
console.log('Uploaded file successfully'); | |
callback(null, {text: 'Uploaded file with great success!'}); | |
// TODO: post a message instead of replying to channel, allowing private conversations between people | |
// request.post({ | |
// url: 'https://slack.com/api/chat.postMessage', | |
// token: SLACK_TOKEN, | |
// channel: channelId, | |
// text: body.file.permalink, | |
// as_user: true | |
// }, (err, res, body) => { | |
// console.log('Sent message to channel', body); | |
// resolve(); | |
// }); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment