2
0
Files
bot/packages/forge/blocks/openai/actions/createSpeech.tsx
2024-05-21 16:08:35 +02:00

109 lines
3.3 KiB
TypeScript

import { option, createAction } from '@typebot.io/forge'
import { defaultOpenAIOptions, openAIVoices } from '../constants'
import OpenAI, { ClientOptions } from 'openai'
import { isNotEmpty } from '@typebot.io/lib'
import { createId } from '@typebot.io/lib/createId'
import { uploadFileToBucket } from '@typebot.io/lib/s3/uploadFileToBucket'
import { auth } from '../auth'
import { baseOptions } from '../baseOptions'
export const createSpeech = createAction({
name: 'Create speech',
auth,
baseOptions,
options: option.object({
model: option.string.layout({
fetcher: 'fetchSpeechModels',
defaultValue: 'tts-1',
placeholder: 'Select a model',
}),
input: option.string.layout({
label: 'Input',
inputType: 'textarea',
}),
voice: option.enum(openAIVoices).layout({
label: 'Voice',
placeholder: 'Select a voice',
}),
saveUrlInVariableId: option.string.layout({
inputType: 'variableDropdown',
label: 'Save URL in variable',
}),
}),
getSetVariableIds: (options) =>
options.saveUrlInVariableId ? [options.saveUrlInVariableId] : [],
fetchers: [
{
id: 'fetchSpeechModels',
dependencies: ['baseUrl', 'apiVersion'],
fetch: async ({ credentials, options }) => {
if (!credentials?.apiKey) return []
const baseUrl = options?.baseUrl ?? defaultOpenAIOptions.baseUrl
const config = {
apiKey: credentials.apiKey,
baseURL: baseUrl ?? defaultOpenAIOptions.baseUrl,
defaultHeaders: {
'api-key': credentials.apiKey,
},
defaultQuery: options?.apiVersion
? {
'api-version': options.apiVersion,
}
: undefined,
} satisfies ClientOptions
const openai = new OpenAI(config)
const models = await openai.models.list()
return (
models.data
.filter((model) => model.id.includes('tts'))
.sort((a, b) => b.created - a.created)
.map((model) => model.id) ?? []
)
},
},
],
run: {
server: async ({ credentials: { apiKey }, options, variables, logs }) => {
if (!options.input) return logs.add('Create speech input is empty')
if (!options.voice) return logs.add('Create speech voice is empty')
if (!options.saveUrlInVariableId)
return logs.add('Create speech save variable is empty')
const config = {
apiKey,
baseURL: options.baseUrl ?? defaultOpenAIOptions.baseUrl,
defaultHeaders: {
'api-key': apiKey,
},
defaultQuery: isNotEmpty(options.apiVersion)
? {
'api-version': options.apiVersion,
}
: undefined,
} satisfies ClientOptions
const openai = new OpenAI(config)
const model = options.model ?? defaultOpenAIOptions.voiceModel
const rawAudio = (await openai.audio.speech.create({
input: options.input,
voice: options.voice,
model,
})) as any
const url = await uploadFileToBucket({
file: Buffer.from((await rawAudio.arrayBuffer()) as ArrayBuffer),
key: `tmp/openai/audio/${createId() + createId()}.mp3`,
mimeType: 'audio/mpeg',
})
variables.set(options.saveUrlInVariableId, url)
},
},
})