-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathspeakerbot.js
More file actions
139 lines (125 loc) · 4.27 KB
/
speakerbot.js
File metadata and controls
139 lines (125 loc) · 4.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/**
* =============================================================================
* 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();
}
}
}