Files
chatrd/js/speakerbot.js
2025-08-25 01:16:23 -04:00

140 lines
4.3 KiB
JavaScript

/**
* =============================================================================
* SpeakerBotClient
* =============================================================================
* Author: Rodrigo Emanuel (VortisRD)
* Created: 2025-08-10
* Description:
* WebSocket client for connecting to Speaker.bot, sending TTS (text-to-speech)
* messages, and handling reconnection logic automatically.
*
* Usage Example:
* -----------------------------------------------------------------------------
* const speakerBot = new SpeakerBotClient({
* host: '127.0.0.1',
* port: 7580,
* voiceAlias: 'Joanna',
*
* onConnect: () => console.log('Connected!'),
* onDisconnect: () => console.log('Disconnected!'),
* onError: (err) => console.error(err),
* onMessage: (msg) => console.log('SpeakerBot says:', msg)
* });
*
* speakerBot.speak("Hello World!");
* -----------------------------------------------------------------------------
*
* Parameters:
* host - IP or hostname of the Speaker.bot server.
* port - Port number for the WebSocket connection.
* reconnectDelay - Time in ms before attempting reconnection.
* voiceAlias - Preferred TTS voice name (string or null).
* onConnect - Callback fired when connection is established.
* onDisconnect - Callback fired when connection is closed.
* onError - Callback fired on connection error.
* onMessage - Callback fired when receiving a message from Speaker.bot.
*
* Dependencies:
* None (uses native WebSocket API)
*
* Notes:
* - Messages sent while disconnected are queued and sent after reconnection.
* - Bad word filter is enabled by default in speak() payload.
*
* License:
* MIT License
* =============================================================================
*/
class SpeakerBotClient {
constructor({
host = '127.0.0.1',
port = 7580,
reconnectDelay = 10000,
voiceAlias = null,
onConnect = () => {},
onDisconnect = () => {},
onError = () => {},
onMessage = () => {}
} = {}) {
this.host = host;
this.port = port;
this.reconnectDelay = reconnectDelay;
this.voiceAlias = voiceAlias;
this.onConnect = onConnect;
this.onDisconnect = onDisconnect;
this.onError = onError;
this.onMessage = onMessage;
this.ws = null;
this.queue = [];
this._manualClose = false; // inicia como false
this.connect();
}
get url() {
return `ws://${this.host}:${this.port}/`;
}
get readyState() {
return this.ws ? this.ws.readyState : WebSocket.CLOSED;
}
connect() {
this._manualClose = false; // reset da flag
console.log('[SpeakerBot] Connecting to Speaker.bot...');
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('[SpeakerBot] Connected to Speaker.bot!');
this.onConnect();
while (this.queue.length > 0) {
this.ws.send(this.queue.shift());
}
};
this.ws.onmessage = (event) => {
this.onMessage(event.data);
};
this.ws.onerror = (error) => {
//console.warn(`[SpeakerBot] Connection error. Reconnecting in ${Math.floor(this.reconnectDelay / 1000)}s...`, error);
//this.onError(error);
};
this.ws.onclose = () => {
this.onDisconnect();
if (!this._manualClose) {
setTimeout(() => this.connect(), this.reconnectDelay);
}
};
}
speak(message) {
const payload = {
id: `speak-${Date.now()}`,
request: 'Speak',
message: message,
voice: this.voiceAlias,
badWordFilter: true
};
const json = JSON.stringify(payload);
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(json);
} else {
console.warn(`[SpeakerBot] Not connected yet. Queuing message...`);
this.queue.push(json);
}
}
disconnect() {
this._manualClose = true; // flag para evitar reconexão automática
if (this.ws) {
this.ws.close();
}
}
}