#I’m interested in trying this out I’m
1 messages · Page 1 of 1 (latest)
For sure. So you're looking for my front-end code, consuming and playing the streaming mp3?
Yeah basically it would be what format the data is coming in and how you are formatting to play it and that should be good for me to translate to similar stuff in Godot
This is my project so far: https://github.com/teddybear082/godot-ai-npc-example. I’m kind of a noob with API stuff
I’m wondering if it might be like the reverse of the wit.ai code I’m using which I mostly borrowed
This is the specific eleven labs script in the project so far: https://github.com/teddybear082/godot-ai-npc-example/blob/main/addons/godot-elevenlabs-tts/ElevenLabsTTS.gd
Example of using an AI NPC in Godot VR, using Godot OpenXR (Godot 3.5.1), Wit.ai, GPT-3.5-turbo, and Godot-tts addon - godot-ai-npc-example/ElevenLabsTTS.gd at main · teddybear082/godot-ai-npc-example
Sorry for the delay. Here's my backend node code for calling out and accepting the stream:
// Voice Synthesis service.
// Powered by Eleven Labs.
const axios = require('axios');
const ELEVEN_LABS_API_KEY = process.env.ELEVEN_LABS_API_KEY;
const ELEVEN_LABS_VOICE_ID = 'EXAVITQu4vr4xnSDxMaL'; // Bella. Try here: https://beta.elevenlabs.io/speech-synthesis
// Synthesize a voice from text.
// Note that this will attempt to read aloud any HTML/emoji/special characters you send in, so you may want to strip them out first.
// Returns a streaming audio buffer of type: audio/mpeg
exports.synthesizeVoice = async (text) => {
const options = {
method: 'POST',
url: https://api.elevenlabs.io/v1/text-to-speech/${ELEVEN_LABS_VOICE_ID}/stream,
headers: {
accept: 'audio/mpeg',
'content-type': 'application/json',
'xi-api-key': ELEVEN_LABS_API_KEY,
},
data: {
"text": text,
"voice_settings": {
"stability": 0.3, // 0-1. 0 is.. a little crazy. 1 sounds perfect but more like reading something.
"similarity_boost": 0
}
},
responseType: 'stream',
};
try {
const res = await axios(options);
return res.data;
} catch (error) {
console.log(error);
if (error.status == 401) {
console.log("Eleven Labs: 401 (Authentication Error). Also happens when you hit your character quota for the month.");
}
throw error;
}
}
And here's how I process it one level up in the code:
exports.sendStreamingEventToClient = async (clientId, eventType, streamingResponse) => {
const client = clientModel.getClient(clientId);
if (client) {
// Listen to the data event and send chunks as they become available
streamingResponse.on('data', chunk => {
const data = { eventType, message: chunk.toString('base64') };
const eventString = data: ${JSON.stringify(data)}\n\n;
// This is dozens of entries per audio file coming back: console.log('Sending to client:', 'length:', eventString.length, 'start:', eventString.slice(0, 40), '...');
sendEventStringToClient(client, eventString);
});
// Normally you would end the response after streaming, but it's our permanent EventSource
// connection with the client, so we leave it open.
// Handle errors in the stream
streamingResponse.on('error', err => {
console.error('Stream error', err);
client.response.status(500).send('sendStreamingEventToClient: Internal Server Error while streaming');
});
} else {
console.log('ERROR: ClientCommService.sendEventToClient: unknown clientId: ' + clientId);
}
}