File size: 13,893 Bytes
f5223c1
ac03bb3
 
 
af38c19
d1f0f2d
2ced09a
 
3a17e83
6e6dab9
62b2fed
 
4e6658c
6938328
 
e940bf5
541cc7d
897b3f0
277b8cc
897b3f0
 
 
 
 
277b8cc
 
 
 
 
 
897b3f0
 
 
 
e950717
 
 
666948d
 
 
62b2fed
 
22b469d
 
 
e940bf5
 
897b3f0
 
8f9b2a4
 
63b7747
 
897b3f0
af38c19
 
 
6e6dab9
 
 
af38c19
6e6dab9
ac03bb3
5095603
 
6ed2c8f
 
5095603
4a1d039
 
 
 
 
6ed2c8f
5095603
6e6dab9
 
 
5095603
077080c
4a1d039
 
5095603
 
 
 
 
4a1d039
5095603
6ed2c8f
 
 
 
077080c
5095603
011422d
 
 
451c088
 
b7cd026
d1331b4
b7cd026
2ced09a
 
 
38880bf
 
 
2ced09a
 
4b79bca
f6eb9d0
 
2ced09a
6e6dab9
077080c
5095603
 
4a1d039
ac03bb3
 
4a1d039
 
 
c5c7ecf
1be3dd1
d1f0f2d
541cc7d
077080c
af38c19
 
 
277b8cc
6e6dab9
af38c19
 
 
6938328
af38c19
 
6e6dab9
 
bc9cd50
277b8cc
 
bc9cd50
277b8cc
 
bc9cd50
277b8cc
1af2928
bc9cd50
 
 
277b8cc
 
9136fd8
277b8cc
 
9136fd8
ab4c27f
 
 
277b8cc
9136fd8
1af2928
9136fd8
 
7dd081a
 
277b8cc
7dd081a
 
 
 
541cc7d
 
7dd081a
 
 
 
f12b690
277b8cc
f12b690
 
 
 
171f6df
1f718de
 
f8ad7ae
10e33e0
ebbfc38
f8ad7ae
ebbfc38
f8ad7ae
 
10e33e0
 
ebbfc38
f12b690
 
 
 
 
 
 
 
 
 
 
 
 
 
 
af8a4b7
e950717
666948d
 
 
 
 
 
e950717
 
666948d
e950717
 
666948d
 
e950717
666948d
e950717
 
666948d
a217bfa
e950717
 
 
666948d
277b8cc
e950717
 
666948d
e950717
 
666948d
e950717
 
 
 
22b469d
666948d
 
 
22b469d
666948d
22b469d
 
ab4c27f
6938328
ab4c27f
 
 
22b469d
 
 
 
666948d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a217bfa
666948d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4e3aa93
 
62b2fed
 
 
 
84b077e
 
 
 
 
 
 
 
 
 
 
 
 
 
62b2fed
 
4e3aa93
 
666948d
 
 
 
 
 
 
 
 
e940bf5
666948d
 
 
 
 
 
 
af8a4b7
277b8cc
af8a4b7
 
 
da5489b
 
af8a4b7
 
8f9b2a4
 
 
 
 
 
 
 
 
 
 
af8a4b7
63b7747
 
 
 
5d33608
1cc6a54
63b7747
 
5d33608
63b7747
 
 
 
 
 
 
 
d4807f3
63b7747
 
 
 
d4807f3
5d33608
63b7747
d4807f3
5d33608
63b7747
 
 
 
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
import { ChatCompletionsRequester } from "../networks/llm_requester.js";
import {
    stop_latest_message_animation,
    start_latest_message_animation,
    create_new_chat_session,
    get_latest_message_content_displayer,
    get_selected_llm_model,
    create_messager,
} from "./chat_operator.js";

import { NewAgentModalWidget } from "../widgets/new_agent_modal_widget.js";

import { screen_scroller } from "./screen_scroller.js";
import { chat_history_storage } from "../storages/chat_history_storage.js";
import { endpoint_storage } from "../storages/endpoint_storage.js";
import { agent_storage } from "../storages/agent_storage.js";

export class ButtonsBinder {
    constructor() {}
    bind() {
        let send_user_input_binder = new SendUserInputButtonBinder();
        send_user_input_binder.bind();
        let new_chat_binder = new NewChatButtonBinder();
        new_chat_binder.bind();
        let toggle_endpoint_and_api_key_items_button_binder =
            new ToggleEndpointAndApiKeyItemsButtonBinder();
        toggle_endpoint_and_api_key_items_button_binder.bind();
        let add_endpoint_and_api_key_item_button_binder =
            new AddEndpointAndApiKeyItemButtonBinder();
        add_endpoint_and_api_key_item_button_binder.bind();
        let scroll_to_bottom_binder = new ScrollToBottomButtonBinder();
        scroll_to_bottom_binder.bind();
        let screenshot_button_binder = new ScreenshotButtonBinder();
        screenshot_button_binder.bind();
        let chat_history_sidebar_toggle_button_binder =
            new ChatHistorySidebarToggleButtonBinder();
        chat_history_sidebar_toggle_button_binder.bind();
        let chat_agents_sidebar_toggle_button_binder =
            new ChatAgentsSidebarToggleButtonBinder();
        chat_agents_sidebar_toggle_button_binder.bind();
        let new_agent_button_binder = new NewAgentButtonBinder();
        new_agent_button_binder.bind();
        let clear_chat_history_button_binder =
            new ClearChatHistoryButtonBinder();
        clear_chat_history_button_binder.bind();
        let clear_chat_agents_button_binder = new ClearChatAgentsButtonBinder();
        clear_chat_agents_button_binder.bind();
        let available_models_select_binder = new AvailableModelsSelectBinder();
        available_models_select_binder.bind();
        let agents_select_binder = new AgentsSelectBinder();
        agents_select_binder.bind();
        let dark_theme_toggle_button_binder = new DarkThemeToggleButtonBinder();
        dark_theme_toggle_button_binder.bind();
    }
}

class SendUserInputButtonBinder {
    constructor() {
        this.requester = null;
    }
    bind() {
        const button = $("#send-user-input");
        button.attr("status", "send").attr("title", "Send");
        button.click(() => {
            this.handle_user_input(button);
        });

        $("#user-input").keypress((event) => {
            if (
                event.key === "Enter" &&
                !event.shiftKey &&
                button.attr("status") === "send"
            ) {
                event.preventDefault();
                this.handle_user_input(button);
            }
        });
    }
    handle_user_input(button) {
        let user_input_content = $("#user-input").val();
        let status = button.attr("status");
        if (status === "send") {
            if (user_input_content === "") {
                return;
            } else {
                this.send(button);
            }
        } else if (status === "stop") {
            this.stop(button);
        } else {
            console.log("No action");
        }
    }

    send(button) {
        let button_icon = button.find("i");
        button.attr("status", "stop").attr("title", "Stop");
        button_icon.removeClass().addClass("fa fa-circle-pause fa-fade-fast");
        let user_input_content = $("#user-input").val();
        console.log(user_input_content);
        // empty user input and reset height
        $("#user-input").val("");
        $("#user-input").css("height", "auto");
        if (get_selected_llm_model() == "notes") {
            create_messager("user", user_input_content);
        } else {
            this.requester = new ChatCompletionsRequester({
                prompt: user_input_content,
            });
            this.requester.create_messager_components();
            start_latest_message_animation();
            this.requester.post().then(() => {
                this.stop(button);
            });
        }
    }

    stop(button) {
        this.requester.stop();
        let button_icon = button.find("i");
        stop_latest_message_animation();
        button.attr("status", "send").attr("title", "Send");
        button_icon
            .removeClass()
            .addClass("fa fa-paper-plane")
            .addClass("icon-success");
        hljs.highlightAll();
        console.log(get_latest_message_content_displayer().data("raw_content"));
        screen_scroller.set_user_scrolling(false);
    }
}

class NewChatButtonBinder {
    constructor() {}
    bind() {
        const button = $("#new-chat-session");
        button.attr("status", "new").attr("title", "New Chat");
        button.click(() => {
            chat_history_storage.save_current_chat_session();
            create_new_chat_session();
        });
    }
}

class ToggleEndpointAndApiKeyItemsButtonBinder {
    constructor() {}
    bind() {
        const button = $("#toggle-endpoint-and-api-key-items-button");
        button.attr("title", "Toggle endpoint and api key items");
        button.click(() => {
            $("#endpoint-and-api-key-items").toggle();
            $("#add-endpoint-and-api-key-item-button").parent().toggle();
        });
    }
}
class AddEndpointAndApiKeyItemButtonBinder {
    constructor() {}
    bind() {
        const button = $("#add-endpoint-and-api-key-item-button");
        button.attr("title", "Add endpoint and api key item");
        button.click(() => {
            if (!$("#endpoint-and-api-key-items").is(":visible")) {
                $("#endpoint-and-api-key-items").toggle();
            }
            endpoint_storage.add_endpoint_and_api_key_item();
        });
        button.parent().hide();
    }
}

class ScrollToBottomButtonBinder {
    constructor() {}
    bind() {
        const button = $("#scroll-to-bottom-button");
        button.attr("title", "Scroll to bottom");
        button.click(() => {
            screen_scroller.set_user_scrolling(false);
            screen_scroller.scroll_to_bottom(true);
        });
    }
}

class ScreenshotButtonBinder {
    constructor() {}
    bind() {
        const button = $("#screenshot-button");
        button.attr("title", "Take screenshot for whole chat");
        button.click(() => {
            let screenshot_padding = 0;
            // default padding is 0.75em (12px)
            // p-1 (4px)(0.25em); p-2 (8px)(0.5em); p-3 (16px)(1em);
            let container_padding = 12;
            let right_offset = 20;
            html2canvas($("#messagers-container")[0], {
                x: -(container_padding + screenshot_padding),
                width:
                    $("#messagers-container").width() +
                    container_padding * 2 +
                    screenshot_padding * 2 +
                    right_offset,
            }).then((canvas) => {
                var link = document.createElement("a");
                let date = new Date();
                let date_string = date.toISOString().split("T")[0];
                let time_string = date
                    .toTimeString()
                    .split(" ")[0]
                    .replace(/:/g, "-");
                let datetime_string = `${date_string}_${time_string}`;
                link.download = `chat_${datetime_string}.png`;
                link.href = canvas.toDataURL("image/png");
                link.click();
            });
        });
    }
}

class ChatHistorySidebarToggleButtonBinder {
    constructor() {
        this.storage_key = "show_chat_history_sidebar";
        this.sidebar_name = "chat-history";
    }
    get_show_history_sidebar_storage() {
        return localStorage.getItem(this.storage_key);
    }
    bind() {
        const sidebar = $(`#${this.sidebar_name}-sidebar`);
        // this line is not to check value as false,
        // but to check item not existed in localStorage
        if (!this.get_show_history_sidebar_storage()) {
            localStorage.setItem(this.storage_key, "true");
        }
        if (this.get_show_history_sidebar_storage() === "true") {
            sidebar.addClass("show");
        }
        const toggle_button = $(`#${this.sidebar_name}-sidebar-toggle-button`);
        toggle_button.attr("title", "Toggle chat history sidebar");
        toggle_button.click(() => {
            sidebar.toggleClass("show");
            localStorage.setItem(
                this.storage_key,
                sidebar.hasClass("show").toString()
            );
        });
        const close_button = $(`#${this.sidebar_name}-sidebar-close-button`);
        close_button.click(() => {
            sidebar.removeClass("show");
            localStorage.setItem(this.storage_key, "false");
        });
    }
}

class ClearChatHistoryButtonBinder {
    constructor() {
        this.sidebar_name = "chat-history";
    }
    bind() {
        const button = $(`#clear-${this.sidebar_name}-button`);
        button.attr("title", "Clear chat history");
        button.click(() => {
            if (confirm("Clear chat history?")) {
                chat_history_storage.clear_database();
            } else {
                console.log("Clear chat history canceled.");
            }
        });
    }
}

class ChatAgentsSidebarToggleButtonBinder {
    constructor() {
        this.storage_key = "show_chat_agents_sidebar";
        this.sidebar_name = "chat-agents";
    }
    get_show_sidebar_storage() {
        return localStorage.getItem(this.storage_key);
    }
    bind() {
        const sidebar = $(`#${this.sidebar_name}-sidebar`);
        // this line is not to check value as false,
        // but to check item not existed in localStorage
        if (!this.get_show_sidebar_storage()) {
            localStorage.setItem(this.storage_key, "true");
        }
        if (this.get_show_sidebar_storage() === "true") {
            sidebar.addClass("show");
        }
        const toggle_button = $(`#${this.sidebar_name}-sidebar-toggle-button`);
        toggle_button.attr("title", "Toggle chat agents sidebar");
        toggle_button.click(() => {
            sidebar.toggleClass("show");
            localStorage.setItem(
                this.storage_key,
                sidebar.hasClass("show").toString()
            );
        });

        const close_button = $(`#${this.sidebar_name}-sidebar-close-button`);
        close_button.click(() => {
            sidebar.removeClass("show");
            localStorage.setItem(this.storage_key, "false");
        });
    }
}

class NewAgentButtonBinder {
    constructor() {}
    bind() {
        const button = $("#new-agent-button");
        button.attr("title", "New agent");
        button.click(() => {
            let new_agent_modal_widget_id = "new-agent-modal";
            let new_agent_modal_widget_parent = $(
                `#${new_agent_modal_widget_id}`
            );
            if (new_agent_modal_widget_parent.length <= 0) {
                let new_agent_modal_widget = new NewAgentModalWidget({
                    widget_id: new_agent_modal_widget_id,
                });
                new_agent_modal_widget.spawn();
                new_agent_modal_widget_parent = $(
                    `#${new_agent_modal_widget_id}`
                );
            }
            new_agent_modal_widget_parent.modal("show");
        });
    }
}

class ClearChatAgentsButtonBinder {
    constructor() {
        this.sidebar_name = "chat-agents";
    }
    bind() {
        const button = $(`#clear-${this.sidebar_name}-button`);
        button.attr("title", "Clear agents");
        button.click(() => {
            if (confirm("Clear agents?")) {
                agent_storage.clear_database();
            } else {
                console.log("Clear agents canceled.");
            }
        });
    }
}

class AvailableModelsSelectBinder {
    constructor() {}
    bind() {
        const select = $("#available-models-select");
        select.change(() => {
            localStorage.setItem("default_model", select.val());
            console.log("set default_model:", select.val());
        });
    }
}

class AgentsSelectBinder {
    constructor() {}
    bind() {
        const select = $("#agents-select");
        select.change(() => {
            localStorage.setItem("default_agent", select.val());
            console.log("set default_agent:", select.val());
        });
    }
}

class DarkThemeToggleButtonBinder {
    constructor() {
        this.storage_key = "theme";
        this.toggle_button = $("#dark-theme-toggle-button");
        window.onload = () => this.set_theme();
    }
    bind() {
        this.toggle_button.click(() => {
            let theme = localStorage.getItem(this.storage_key);
            if (theme === "dark") {
                localStorage.setItem(this.storage_key, "light");
            } else {
                localStorage.setItem(this.storage_key, "dark");
            }
            this.set_theme();
        });
        DarkReader.setFetchMethod(window.fetch);
    }
    set_theme() {
        let theme = localStorage.getItem(this.storage_key);
        if (theme === "dark") {
            DarkReader.enable();
            this.toggle_button.attr("title", "Switch to Light theme");
        } else {
            DarkReader.disable();
            this.toggle_button.attr("title", "Switch to Dark theme");
        }
        console.log("set theme:", theme);
    }
}