-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtext-listener.js
131 lines (112 loc) · 4.2 KB
/
text-listener.js
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
const WebSocket = require("ws");
const { SpeakingQueue, SpeakText } = require("./speaking-queue");
const { OpenAI } = require("langchain");
const { initializeAgentExecutor, Tool, AgentExecutor } = require("langchain/agents");
const { BaseLLM } = require("langchain/llms");
const { DynamicTool } = require("langchain/tools");
class TextListener {
/** @type {WebSocket} chatWebSocket */
chatWebSocket;
/** @type {SpeakingQueue} */
speakingQueue;
/** @type {Object} */
texts;
/** @type {String} */
voice;
/** @type {String} */
msg;
/** @type {Tool[]} */
tools;
/** @type {BaseLLM} */
model;
/** @type {AgentExecutor} */
executor;
constructor(chatWebSocket) {
this.texts = {};
this.msg = '';
this.chatWebSocket = chatWebSocket;
this.speakingQueue = new SpeakingQueue();
this.model = new OpenAI({ temperature: 0, openAIApiKey: process.env.OPENAI_API_KEY });
this.voice = "Polly.Matthew-Neural";
this.tools = [
new DynamicTool({
name: "CHANGE_VOICE",
description: "call this when the user wants to change the voice",
func: (chat) => this.handleCommand('change-voice'),
}),
new DynamicTool({
name: "SEND_CHAT",
description: "call this when the user is done speaking and doesn't want to perform any special action",
func: (chat) => this.handleCommand('send-chat'),
}),
];
}
async initialize() {
this.executor = await initializeAgentExecutor(
this.tools,
this.model,
"zero-shot-react-description"
);
}
forceState(state) {
this.texts = state.texts;
this.msg = state.msg;
}
async onMessage(assemblyMsg) {
const res = JSON.parse(assemblyMsg.data);
this.texts[res.audio_start] = res.text;
const keys = Object.keys(this.texts);
keys.sort((a, b) => a - b);
this.msg = '';
for (const key of keys) {
if (this.texts[key]) {
this.msg += ` ${this.texts[key]}`;
}
}
// const detectedCommands = this.detectCommand();
// for (const command of detectedCommands) {
// this.handleCommand(command);
// }
if (this._endsOnPause()) {
const text = this.msg.substring(0, this.msg.length - 1);
const input = `I need to use only one of my tools to act on the following text: ${text}`;
await this.executor.call({ input });
console.log(`acted on ${text}`);
}
console.log(this.msg);
}
_endsOnPause() {
return this.msg.substring(this.msg.length - 1).match(/[\.\?!,:]/);
}
detectCommand() {
const detectedCommands = [];
if (this.msg.toLocaleLowerCase().includes('command') && this.msg.toLocaleLowerCase().includes('clear')) {
detectedCommands.push('clear');
}
if (this.msg.toLocaleLowerCase().includes('command') && this.msg.toLocaleLowerCase().includes('send')) {
detectedCommands.push('send-chat');
}
return detectedCommands;
}
handleCommand(command) {
switch (command) {
case 'send-chat':
this.chatWebSocket.send(JSON.stringify({ type: "console", message: JSON.stringify({ texts: this.texts, msg: this.msg }) }));
this.msg.toLocaleLowerCase().indexOf('command') > -1 && (this.msg = this.msg.replace(/command .*/g, '').trim());
this.chatWebSocket.send(JSON.stringify({ type: "sendChat", message: this.msg }));
this.texts = {};
this.msg = '';
this.speakingQueue.clear();
break;
case 'change-voice':
this.texts = {};
this.msg = '';
this.speakingQueue.clear();
this.voice = this.voice === "Polly.Matthew-Neural" ? "Polly.Joanna-Neural" : "Polly.Matthew-Neural";
this.speakingQueue.enqueue(new SpeakText(`Voice changed!`));
default:
break;
}
}
}
exports.TextListener = TextListener;