Skip to content

Commit

Permalink
Merge pull request #328 from harmony-one/voicehk
Browse files Browse the repository at this point in the history
Added voicehk and voicehkf commands
  • Loading branch information
theofandrich authored Oct 2, 2023
2 parents 41c8e38 + f24fbcb commit 79656ad
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 10 deletions.
29 changes: 29 additions & 0 deletions src/elevenlabs/elevenlabsClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import axios, { type AxiosInstance } from 'axios'

export class ElevenlabsClient {
private readonly _token: string
private readonly _httpClient: AxiosInstance
constructor (apiKey: string) {
this._token = apiKey

this._httpClient = axios.create({
baseURL: 'https://api.elevenlabs.io',
headers: {
'Content-Type': 'application/json',
Accept: 'audio/mpeg',
'xi-api-key': apiKey
}
})
}

public async textToSpeech ({ text, voiceId }: { text: string, voiceId: string }): Promise<string | Uint8Array | null | undefined> {
return await this._httpClient.post(`/v1/text-to-speech/${voiceId}`, {
text: 'string',
model_id: 'eleven_monolingual_v1',
voice_settings: {
stability: 0.5,
similarity_boost: 0.5
}
})
}
}
Empty file added src/elevenlabs/test.ts
Empty file.
10 changes: 8 additions & 2 deletions src/google-cloud/gcTextToSpeechClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@ import GcTextToSpeech, { type TextToSpeechClient } from '@google-cloud/text-to-s
import config from '../config'
import type { CredentialBody } from 'google-auth-library/build/src/auth/credentials'

export interface TextToSpeechParams {
text: string
languageCode: 'en-US' | 'yue-Hant-HK' | 'ru-RU'
gender: 'MALE' | 'FEMALE'
}

class GcTextToSpeechClient {
private readonly _client: TextToSpeechClient
constructor (credentials: CredentialBody) {
this._client = new GcTextToSpeech.TextToSpeechClient({ credentials })
}

async textToSpeech (text: string): Promise<string | Uint8Array | null | undefined> {
async textToSpeech ({ text, languageCode, gender }: TextToSpeechParams): Promise<string | Uint8Array | null | undefined> {
const ssml = `<speak>${text}</speak>`

const [response] = await this._client.synthesizeSpeech({
input: { ssml },
voice: { languageCode: 'en-US', ssmlGender: 'MALE' },
voice: { languageCode, ssmlGender: gender },
audioConfig: { audioEncoding: 'OGG_OPUS' }
})

Expand Down
41 changes: 34 additions & 7 deletions src/modules/text-to-speech/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import { InputFile } from 'grammy'
import type { Logger } from 'pino'
import type { BotPayments } from '../payment'
import type { OnMessageContext, PayableBot } from '../types'
import { gcTextToSpeedClient } from '../../google-cloud/gcTextToSpeechClient'
import { gcTextToSpeedClient, type TextToSpeechParams } from '../../google-cloud/gcTextToSpeechClient'

enum SupportedCommands {
VOICE = 'voice',
VOICEHK = 'voicehk',
VOICEHKF = 'voicehkf',
VOICERU = 'voiceru',
}

export class TextToSpeechBot implements PayableBot {
private readonly payments: BotPayments
Expand All @@ -22,7 +29,7 @@ export class TextToSpeechBot implements PayableBot {
}

public isSupportedEvent (ctx: OnMessageContext): boolean {
return ctx.hasCommand('voice')
return ctx.hasCommand(Object.values(SupportedCommands))
}

public getEstimatedPrice (ctx: OnMessageContext): number {
Expand All @@ -39,14 +46,34 @@ export class TextToSpeechBot implements PayableBot {
}

public async onEvent (ctx: OnMessageContext): Promise<void> {
if (ctx.hasCommand('voice')) {
if (ctx.hasCommand(SupportedCommands.VOICE)) {
const text = this.getTextFromMessage(ctx)
await this.onTextToSpeech(ctx, { text, gender: 'MALE', languageCode: 'en-US' })
return
}

if (ctx.hasCommand(SupportedCommands.VOICEHK)) {
const text = this.getTextFromMessage(ctx)
await this.onTextToSpeech(ctx, text)
await this.onTextToSpeech(ctx, { text, gender: 'MALE', languageCode: 'yue-Hant-HK' })
return
}

if (ctx.hasCommand(SupportedCommands.VOICEHKF)) {
const text = this.getTextFromMessage(ctx)
await this.onTextToSpeech(ctx, { text, gender: 'FEMALE', languageCode: 'yue-Hant-HK' })
return
}

if (ctx.hasCommand(SupportedCommands.VOICERU)) {
const text = this.getTextFromMessage(ctx)
await this.onTextToSpeech(ctx, { text, gender: 'FEMALE', languageCode: 'ru-RU' })
}
}

public async onTextToSpeech (ctx: OnMessageContext, message: string): Promise<void> {
if (!message) {
public async onTextToSpeech (ctx: OnMessageContext, params: TextToSpeechParams): Promise<void> {
const { text, gender, languageCode } = params

if (!params.text) {
await ctx.reply('/voice command should contain text.')
return
}
Expand All @@ -57,7 +84,7 @@ export class TextToSpeechBot implements PayableBot {

const progressMessage = await ctx.reply('Generating...')

const voiceResult = await gcTextToSpeedClient.textToSpeech(message)
const voiceResult = await gcTextToSpeedClient.textToSpeech({ text, gender, languageCode })

if (!voiceResult) {
await ctx.api.editMessageText(ctx.chat.id, progressMessage.message_id, 'An error occurred during the process of generating the message.')
Expand Down
2 changes: 1 addition & 1 deletion src/modules/voice-translate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class VoiceTranslateBot implements PayableBot {

const translateResult = await translator.translateText(resultText, null, 'en-US')

const voiceResult = await gcTextToSpeedClient.textToSpeech(translateResult.text)
const voiceResult = await gcTextToSpeedClient.textToSpeech({ text: translateResult.text, gender: 'MALE', languageCode: 'en-US' })

if (!voiceResult) {
await ctx.reply('voice generation error')
Expand Down

0 comments on commit 79656ad

Please sign in to comment.