Skip to content

Commit c3d78f8

Browse files
committed
SimpleChatTC:Cleanup:Make main chat related classes importable
Have main classes defined independent of and away from runtime flow Move out the entry point including runtime instantiation of the core Me class (which inturn brings other class instances as neede) into its own main.js file. With this one should be able to import simplechat.js into other files, where one might need the SimpleChat or MultiChat or Me class definitions.
1 parent a65f4a0 commit c3d78f8

File tree

3 files changed

+81
-59
lines changed

3 files changed

+81
-59
lines changed

tools/server/public_simplechat/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
<script type="importmap">
1212
{
1313
"imports": {
14+
"simplechat": "./simplechat.js"
1415
"datautils": "./datautils.mjs",
1516
"ui": "./ui.mjs"
1617
}
1718
}
1819
</script>
19-
<script src="simplechat.js" type="module" defer></script>
20+
<script src="main.js" type="module" defer></script>
2021
<link rel="stylesheet" href="simplechat.css" />
2122
</head>
2223
<body>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// @ts-check
2+
// A simple completions and chat/completions test related web front end logic
3+
// by Humans for All
4+
5+
6+
import * as mChatMagic from './simplechat.js'
7+
import * as tools from "./tools.mjs"
8+
import * as du from "./datautils.mjs";
9+
10+
11+
12+
/** @type {mChatMagic.Me} */
13+
let gMe;
14+
15+
function startme() {
16+
console.log("INFO:SimpleChat:StartMe:Starting...");
17+
gMe = new mChatMagic.Me();
18+
gMe.debug_disable();
19+
// @ts-ignore
20+
document["gMe"] = gMe;
21+
// @ts-ignore
22+
document["du"] = du;
23+
// @ts-ignore
24+
document["tools"] = tools;
25+
tools.init().then((toolNames)=>gMe.tools.toolNames=toolNames).then(()=>gMe.multiChat.chat_show(gMe.multiChat.curChatId))
26+
for (let cid of gMe.defaultChatIds) {
27+
gMe.multiChat.new_chat_session(cid);
28+
}
29+
gMe.multiChat.setup_ui(gMe.defaultChatIds[0], true);
30+
gMe.multiChat.show_sessions();
31+
}
32+
33+
document.addEventListener("DOMContentLoaded", startme);

tools/server/public_simplechat/simplechat.js

Lines changed: 46 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @ts-check
2-
// A simple completions and chat/completions test related web front end logic
2+
// Core classes which provide a simple implementation of handshake with ai server's completions and chat/completions endpoints
3+
// as well as related web front end logic for basic usage and testing.
34
// by Humans for All
45

56
import * as du from "./datautils.mjs";
@@ -277,7 +278,10 @@ class ChatMessageEx {
277278
}
278279

279280

280-
function usage_note() {
281+
/**
282+
* @param {number} iRecentUserMsgCnt
283+
*/
284+
function usage_note(iRecentUserMsgCnt) {
281285
let sUsageNote = `
282286
<details>
283287
<summary id="UsageNote" class="role-system">Usage Note</summary>
@@ -293,7 +297,7 @@ function usage_note() {
293297
<li> If ai assistant requests a tool call, verify same before triggering.</li>
294298
<li> submit tool response placed into user query/response text area</li>
295299
</ul>
296-
<li> ContextWindow = [System, Last[${gMe.chatProps.iRecentUserMsgCnt-1}] User Query/Resp, Cur Query].</li>
300+
<li> ContextWindow = [System, Last[${iRecentUserMsgCnt}] User Query/Resp, Cur Query].</li>
297301
<ul class="ul2">
298302
<li> ChatHistInCtxt, MaxTokens, ModelCtxt window to expand</li>
299303
</ul>
@@ -311,8 +315,9 @@ class SimpleChat {
311315

312316
/**
313317
* @param {string} chatId
318+
* @param {Me} me
314319
*/
315-
constructor(chatId) {
320+
constructor(chatId, me) {
316321
this.chatId = chatId;
317322
/**
318323
* Maintain in a form suitable for common LLM web service chat/completions' messages entry
@@ -321,6 +326,7 @@ class SimpleChat {
321326
this.xchat = [];
322327
this.iLastSys = -1;
323328
this.latestResponse = new ChatMessageEx();
329+
this.me = me;
324330
}
325331

326332
clear() {
@@ -485,14 +491,14 @@ class SimpleChat {
485491

486492
/**
487493
* Setup the fetch headers.
488-
* It picks the headers from gMe.headers.
494+
* It picks the headers from this.me.headers.
489495
* It inserts Authorization only if its non-empty.
490496
* @param {string} apiEP
491497
*/
492498
fetch_headers(apiEP) {
493499
let headers = new Headers();
494-
for(let k in gMe.headers) {
495-
let v = gMe.headers[k];
500+
for(let k in this.me.headers) {
501+
let v = this.me.headers[k];
496502
if ((k == "Authorization") && (v.trim() == "")) {
497503
continue;
498504
}
@@ -509,13 +515,13 @@ class SimpleChat {
509515
* @param {Object<string, any>} obj
510516
*/
511517
request_jsonstr_extend(obj) {
512-
for(let k in gMe.apiRequestOptions) {
513-
obj[k] = gMe.apiRequestOptions[k];
518+
for(let k in this.me.apiRequestOptions) {
519+
obj[k] = this.me.apiRequestOptions[k];
514520
}
515-
if (gMe.chatProps.stream) {
521+
if (this.me.chatProps.stream) {
516522
obj["stream"] = true;
517523
}
518-
if (gMe.tools.enabled) {
524+
if (this.me.tools.enabled) {
519525
obj["tools"] = tools.meta();
520526
}
521527
return JSON.stringify(obj);
@@ -526,7 +532,7 @@ class SimpleChat {
526532
*/
527533
request_messages_jsonstr() {
528534
let req = {
529-
messages: this.recent_chat_ns(gMe.chatProps.iRecentUserMsgCnt),
535+
messages: this.recent_chat_ns(this.me.chatProps.iRecentUserMsgCnt),
530536
}
531537
return this.request_jsonstr_extend(req);
532538
}
@@ -538,7 +544,7 @@ class SimpleChat {
538544
request_prompt_jsonstr(bInsertStandardRolePrefix) {
539545
let prompt = "";
540546
let iCnt = 0;
541-
for(const msg of this.recent_chat(gMe.chatProps.iRecentUserMsgCnt)) {
547+
for(const msg of this.recent_chat(this.me.chatProps.iRecentUserMsgCnt)) {
542548
iCnt += 1;
543549
if (iCnt > 1) {
544550
prompt += "\n";
@@ -562,7 +568,7 @@ class SimpleChat {
562568
if (apiEP == ApiEP.Type.Chat) {
563569
return this.request_messages_jsonstr();
564570
} else {
565-
return this.request_prompt_jsonstr(gMe.chatProps.bCompletionInsertStandardRolePrefix);
571+
return this.request_prompt_jsonstr(this.me.chatProps.bCompletionInsertStandardRolePrefix);
566572
}
567573
}
568574

@@ -676,7 +682,7 @@ class SimpleChat {
676682
*/
677683
async handle_response(resp, apiEP, elDiv) {
678684
let theResp = null;
679-
if (gMe.chatProps.stream) {
685+
if (this.me.chatProps.stream) {
680686
try {
681687
theResp = await this.handle_response_multipart(resp, apiEP, elDiv);
682688
this.latestResponse.clear();
@@ -690,7 +696,7 @@ class SimpleChat {
690696
} else {
691697
theResp = await this.handle_response_oneshot(resp, apiEP);
692698
}
693-
if (gMe.chatProps.bTrimGarbage) {
699+
if (this.me.chatProps.bTrimGarbage) {
694700
let origMsg = theResp.ns.content;
695701
theResp.ns.content = du.trim_garbage_at_end(origMsg);
696702
theResp.trimmedContent = origMsg.substring(theResp.ns.content.length);
@@ -756,7 +762,11 @@ class SimpleChat {
756762

757763
class MultiChatUI {
758764

759-
constructor() {
765+
/**
766+
* @param {Me} me
767+
*/
768+
constructor(me) {
769+
this.me = me
760770
/** @type {Object<string, SimpleChat>} */
761771
this.simpleChats = {};
762772
/** @type {string} */
@@ -842,10 +852,10 @@ class MultiChatUI {
842852
this.elInToolName.dataset.tool_call_id = ar.ns.tool_calls[0].id
843853
this.elInToolArgs.value = ar.ns.tool_calls[0].function.arguments
844854
this.elBtnTool.disabled = false
845-
if ((gMe.tools.autoSecs > 0) && (bAuto)) {
855+
if ((this.me.tools.autoSecs > 0) && (bAuto)) {
846856
this.timers.toolcallTriggerClick = setTimeout(()=>{
847857
this.elBtnTool.click()
848-
}, gMe.tools.autoSecs*this.TimePeriods.ToolCallAutoSecsTimeUnit)
858+
}, this.me.tools.autoSecs*this.TimePeriods.ToolCallAutoSecsTimeUnit)
849859
}
850860
} else {
851861
this.elDivTool.hidden = true
@@ -992,7 +1002,7 @@ class MultiChatUI {
9921002
this.ui_reset_toolcall_as_needed(new ChatMessageEx());
9931003
}
9941004
this.elLastChatMessage = null
995-
let chatToShow = chat.recent_chat(gMe.chatProps.iRecentUserMsgCnt);
1005+
let chatToShow = chat.recent_chat(this.me.chatProps.iRecentUserMsgCnt);
9961006
for(const [i, x] of chatToShow.entries()) {
9971007
let iFromLast = (chatToShow.length - 1)-i
9981008
let nextMsg = undefined
@@ -1005,9 +1015,9 @@ class MultiChatUI {
10051015
/** @type{HTMLElement} */(this.elLastChatMessage).scrollIntoView(false); // Stupid ts-check js-doc intersection ???
10061016
} else {
10071017
if (bClear) {
1008-
this.elDivChat.innerHTML = usage_note();
1009-
gMe.setup_load(this.elDivChat, chat);
1010-
gMe.show_info(this.elDivChat, bShowInfoAll);
1018+
this.elDivChat.innerHTML = usage_note(this.me.chatProps.iRecentUserMsgCnt-1);
1019+
this.me.setup_load(this.elDivChat, chat);
1020+
this.me.show_info(this.elDivChat, bShowInfoAll);
10111021
}
10121022
}
10131023
return true
@@ -1030,7 +1040,7 @@ class MultiChatUI {
10301040

10311041
this.elBtnSettings.addEventListener("click", (ev)=>{
10321042
this.elDivChat.replaceChildren();
1033-
gMe.show_settings(this.elDivChat);
1043+
this.me.show_settings(this.elDivChat);
10341044
});
10351045
this.elBtnClearChat.addEventListener("click", (ev)=>{
10361046
this.simpleChats[this.curChatId].clear()
@@ -1043,7 +1053,7 @@ class MultiChatUI {
10431053
if (this.elInUser.disabled) {
10441054
return;
10451055
}
1046-
this.handle_user_submit(this.curChatId, gMe.chatProps.apiEP).catch((/** @type{Error} */reason)=>{
1056+
this.handle_user_submit(this.curChatId, this.me.chatProps.apiEP).catch((/** @type{Error} */reason)=>{
10471057
let msg = `ERRR:SimpleChat\nMCUI:HandleUserSubmit:${this.curChatId}\n${reason.name}:${reason.message}`;
10481058
console.error(msg.replace("\n", ":"));
10491059
alert(msg);
@@ -1065,17 +1075,17 @@ class MultiChatUI {
10651075
this.timers.toolcallResponseTimeout = undefined
10661076
let chat = this.simpleChats[cid];
10671077
let limitedData = data
1068-
if (gMe.tools.iResultMaxDataLength > 0) {
1069-
if (data.length > gMe.tools.iResultMaxDataLength) {
1070-
limitedData = data.slice(0, gMe.tools.iResultMaxDataLength) + `\n\n\nALERT: Data too long, was chopped ....`
1078+
if (this.me.tools.iResultMaxDataLength > 0) {
1079+
if (data.length > this.me.tools.iResultMaxDataLength) {
1080+
limitedData = data.slice(0, this.me.tools.iResultMaxDataLength) + `\n\n\nALERT: Data too long, was chopped ....`
10711081
}
10721082
}
10731083
chat.add(new ChatMessageEx(Roles.ToolTemp, ChatMessageEx.createToolCallResultAllInOne(tcid, name, limitedData)))
10741084
if (this.chat_show(cid)) {
1075-
if (gMe.tools.autoSecs > 0) {
1085+
if (this.me.tools.autoSecs > 0) {
10761086
this.timers.toolcallResponseSubmitClick = setTimeout(()=>{
10771087
this.elBtnUser.click()
1078-
}, gMe.tools.autoSecs*this.TimePeriods.ToolCallAutoSecsTimeUnit)
1088+
}, this.me.tools.autoSecs*this.TimePeriods.ToolCallAutoSecsTimeUnit)
10791089
}
10801090
}
10811091
this.ui_reset_userinput(false)
@@ -1113,7 +1123,7 @@ class MultiChatUI {
11131123
* @param {boolean} bSwitchSession
11141124
*/
11151125
new_chat_session(chatId, bSwitchSession=false) {
1116-
this.simpleChats[chatId] = new SimpleChat(chatId);
1126+
this.simpleChats[chatId] = new SimpleChat(chatId, this.me);
11171127
if (bSwitchSession) {
11181128
this.handle_session_switch(chatId);
11191129
}
@@ -1143,7 +1153,7 @@ class MultiChatUI {
11431153
// So if user wants to simulate a multi-chat based completion query,
11441154
// they will have to enter the full thing, as a suitable multiline
11451155
// user input/query.
1146-
if ((apiEP == ApiEP.Type.Completion) && (gMe.chatProps.bCompletionFreshChatAlways)) {
1156+
if ((apiEP == ApiEP.Type.Completion) && (this.me.chatProps.bCompletionFreshChatAlways)) {
11471157
chat.clear();
11481158
}
11491159

@@ -1167,7 +1177,7 @@ class MultiChatUI {
11671177
this.elInUser.disabled = true;
11681178

11691179
try {
1170-
let theResp = await chat.handle_chat_hs(gMe.baseURL, apiEP, this.elDivChat)
1180+
let theResp = await chat.handle_chat_hs(this.me.baseURL, apiEP, this.elDivChat)
11711181
if (chatId == this.curChatId) {
11721182
this.chat_show(chatId);
11731183
if (theResp.trimmedContent.length > 0) {
@@ -1206,7 +1216,7 @@ class MultiChatUI {
12061216
chat.add(new ChatMessageEx(Roles.ToolTemp, ChatMessageEx.createToolCallResultAllInOne(toolCallId, toolname, `Tool/Function call ${toolname} taking too much time, aborting...`)))
12071217
this.chat_show(chat.chatId)
12081218
this.ui_reset_userinput(false)
1209-
}, gMe.tools.toolCallResponseTimeoutMS)
1219+
}, this.me.tools.toolCallResponseTimeoutMS)
12101220
}
12111221
}
12121222

@@ -1312,12 +1322,12 @@ const SearchURLS = {
13121322
}
13131323

13141324

1315-
class Me {
1325+
export class Me {
13161326

13171327
constructor() {
13181328
this.baseURL = "http://127.0.0.1:8080";
13191329
this.defaultChatIds = [ "Default", "Other" ];
1320-
this.multiChat = new MultiChatUI();
1330+
this.multiChat = new MultiChatUI(this);
13211331
this.tools = {
13221332
enabled: true,
13231333
proxyUrl: "http://127.0.0.1:3128",
@@ -1462,25 +1472,3 @@ class Me {
14621472
}
14631473

14641474

1465-
/** @type {Me} */
1466-
let gMe;
1467-
1468-
function startme() {
1469-
console.log("INFO:SimpleChat:StartMe:Starting...");
1470-
gMe = new Me();
1471-
gMe.debug_disable();
1472-
// @ts-ignore
1473-
document["gMe"] = gMe;
1474-
// @ts-ignore
1475-
document["du"] = du;
1476-
// @ts-ignore
1477-
document["tools"] = tools;
1478-
tools.init().then((toolNames)=>gMe.tools.toolNames=toolNames).then(()=>gMe.multiChat.chat_show(gMe.multiChat.curChatId))
1479-
for (let cid of gMe.defaultChatIds) {
1480-
gMe.multiChat.new_chat_session(cid);
1481-
}
1482-
gMe.multiChat.setup_ui(gMe.defaultChatIds[0], true);
1483-
gMe.multiChat.show_sessions();
1484-
}
1485-
1486-
document.addEventListener("DOMContentLoaded", startme);

0 commit comments

Comments
 (0)