diff options
Diffstat (limited to 'examples/server/public_simplechat/simplechat.js')
-rw-r--r-- | examples/server/public_simplechat/simplechat.js | 554 |
1 files changed, 423 insertions, 131 deletions
diff --git a/examples/server/public_simplechat/simplechat.js b/examples/server/public_simplechat/simplechat.js index 0c48da87..25afb256 100644 --- a/examples/server/public_simplechat/simplechat.js +++ b/examples/server/public_simplechat/simplechat.js @@ -2,6 +2,9 @@ // A simple completions and chat/completions test related web front end logic // by Humans for All +import * as du from "./datautils.mjs"; +import * as ui from "./ui.mjs" + class Roles { static System = "system"; static User = "user"; @@ -9,40 +12,65 @@ class Roles { } class ApiEP { - static Chat = "chat"; - static Completion = "completion"; + static Type = { + Chat: "chat", + Completion: "completion", + } + static UrlSuffix = { + 'chat': `/chat/completions`, + 'completion': `/completions`, + } + + /** + * Build the url from given baseUrl and apiEp id. + * @param {string} baseUrl + * @param {string} apiEP + */ + static Url(baseUrl, apiEP) { + if (baseUrl.endsWith("/")) { + baseUrl = baseUrl.substring(0, baseUrl.length-1); + } + return `${baseUrl}${this.UrlSuffix[apiEP]}`; + } + } + let gUsageMsg = ` <p class="role-system">Usage</p> <ul class="ul1"> - <li> Set system prompt above, to try control ai response charactersitic, if model supports same.</li> + <li> System prompt above, to try control ai response characteristics.</li> <ul class="ul2"> - <li> Completion mode normally wont have a system prompt.</li> + <li> Completion mode - no system prompt normally.</li> </ul> + <li> Use shift+enter for inserting enter/newline.</li> <li> Enter your query to ai assistant below.</li> - <ul class="ul2"> - <li> Completion mode doesnt insert user/role: prefix implicitly.</li> - <li> Use shift+enter for inserting enter/newline.</li> - </ul> <li> Default ContextWindow = [System, Last Query+Resp, Cur Query].</li> <ul class="ul2"> - <li> experiment iRecentUserMsgCnt, max_tokens, model ctxt window to expand</li> + <li> ChatHistInCtxt, MaxTokens, ModelCtxt window to expand</li> </ul> </ul> `; + /** @typedef {{role: string, content: string}[]} ChatMessages */ +/** @typedef {{iLastSys: number, xchat: ChatMessages}} SimpleChatODS */ + class SimpleChat { - constructor() { + /** + * @param {string} chatId + */ + constructor(chatId) { + this.chatId = chatId; /** * Maintain in a form suitable for common LLM web service chat/completions' messages entry * @type {ChatMessages} */ this.xchat = []; this.iLastSys = -1; + this.latestResponse = ""; } clear() { @@ -50,6 +78,27 @@ class SimpleChat { this.iLastSys = -1; } + ods_key() { + return `SimpleChat-${this.chatId}` + } + + save() { + /** @type {SimpleChatODS} */ + let ods = {iLastSys: this.iLastSys, xchat: this.xchat}; + localStorage.setItem(this.ods_key(), JSON.stringify(ods)); + } + + load() { + let sods = localStorage.getItem(this.ods_key()); + if (sods == null) { + return; + } + /** @type {SimpleChatODS} */ + let ods = JSON.parse(sods); + this.iLastSys = ods.iLastSys; + this.xchat = ods.xchat; + } + /** * Recent chat messages. * If iRecentUserMsgCnt < 0 @@ -95,6 +144,15 @@ class SimpleChat { } /** + * Collate the latest response from the server/ai-model, as it is becoming available. + * This is mainly useful for the stream mode. + * @param {string} content + */ + append_response(content) { + this.latestResponse += content; + } + + /** * Add an entry into xchat * @param {string} role * @param {string|undefined|null} content @@ -107,6 +165,7 @@ class SimpleChat { if (role == Roles.System) { this.iLastSys = this.xchat.length - 1; } + this.save(); return true; } @@ -121,10 +180,8 @@ class SimpleChat { } let last = undefined; for(const x of this.recent_chat(gMe.iRecentUserMsgCnt)) { - let entry = document.createElement("p"); + let entry = ui.el_create_append_p(`${x.role}: ${x.content}`, div); entry.className = `role-${x.role}`; - entry.innerText = `${x.role}: ${x.content}`; - div.appendChild(entry); last = entry; } if (last !== undefined) { @@ -132,21 +189,45 @@ class SimpleChat { } else { if (bClear) { div.innerHTML = gUsageMsg; + gMe.setup_load(div, this); gMe.show_info(div); } } + return last; + } + + /** + * Setup the fetch headers. + * It picks the headers from gMe.headers. + * It inserts Authorization only if its non-empty. + * @param {string} apiEP + */ + fetch_headers(apiEP) { + let headers = new Headers(); + for(let k in gMe.headers) { + let v = gMe.headers[k]; + if ((k == "Authorization") && (v.trim() == "")) { + continue; + } + headers.append(k, v); + } + return headers; } /** * Add needed fields wrt json object to be sent wrt LLM web services completions endpoint. * The needed fields/options are picked from a global object. + * Add optional stream flag, if required. * Convert the json into string. * @param {Object} obj */ - request_jsonstr(obj) { + request_jsonstr_extend(obj) { for(let k in gMe.chatRequestOptions) { obj[k] = gMe.chatRequestOptions[k]; } + if (gMe.bStream) { + obj["stream"] = true; + } return JSON.stringify(obj); } @@ -157,7 +238,7 @@ class SimpleChat { let req = { messages: this.recent_chat(gMe.iRecentUserMsgCnt), } - return this.request_jsonstr(req); + return this.request_jsonstr_extend(req); } /** @@ -180,7 +261,60 @@ class SimpleChat { let req = { prompt: prompt, } - return this.request_jsonstr(req); + return this.request_jsonstr_extend(req); + } + + /** + * Return a string form of json object suitable for specified api endpoint. + * @param {string} apiEP + */ + request_jsonstr(apiEP) { + if (apiEP == ApiEP.Type.Chat) { + return this.request_messages_jsonstr(); + } else { + return this.request_prompt_jsonstr(gMe.bCompletionInsertStandardRolePrefix); + } + } + + /** + * Extract the ai-model/assistant's response from the http response got. + * Optionally trim the message wrt any garbage at the end. + * @param {any} respBody + * @param {string} apiEP + */ + response_extract(respBody, apiEP) { + let assistant = ""; + if (apiEP == ApiEP.Type.Chat) { + assistant = respBody["choices"][0]["message"]["content"]; + } else { + try { + assistant = respBody["choices"][0]["text"]; + } catch { + assistant = respBody["content"]; + } + } + return assistant; + } + + /** + * Extract the ai-model/assistant's response from the http response got in streaming mode. + * @param {any} respBody + * @param {string} apiEP + */ + response_extract_stream(respBody, apiEP) { + let assistant = ""; + if (apiEP == ApiEP.Type.Chat) { + if (respBody["choices"][0]["finish_reason"] !== "stop") { + assistant = respBody["choices"][0]["delta"]["content"]; + } + } else { + try { + assistant = respBody["choices"][0]["text"]; + } catch { + assistant = respBody["content"]; + } + } + return assistant; } /** @@ -239,53 +373,99 @@ class SimpleChat { return sysPrompt; } -} - -let gBaseURL = "http://127.0.0.1:8080"; -let gChatURL = { - 'chat': `${gBaseURL}/chat/completions`, - 'completion': `${gBaseURL}/completions`, -} + /** + * Handle the multipart response from server/ai-model + * @param {Response} resp + * @param {string} apiEP + * @param {HTMLDivElement} elDiv + */ + async handle_response_multipart(resp, apiEP, elDiv) { + let elP = ui.el_create_append_p("", elDiv); + if (!resp.body) { + throw Error("ERRR:SimpleChat:SC:HandleResponseMultiPart:No body..."); + } + let tdUtf8 = new TextDecoder("utf-8"); + let rr = resp.body.getReader(); + this.latestResponse = ""; + let xLines = new du.NewLines(); + while(true) { + let { value: cur, done: done } = await rr.read(); + if (cur) { + let curBody = tdUtf8.decode(cur, {stream: true}); + console.debug("DBUG:SC:PART:Str:", curBody); + xLines.add_append(curBody); + } + while(true) { + let curLine = xLines.shift(!done); + if (curLine == undefined) { + break; + } + if (curLine.trim() == "") { + continue; + } + if (curLine.startsWith("data:")) { + curLine = curLine.substring(5); + } + let curJson = JSON.parse(curLine); + console.debug("DBUG:SC:PART:Json:", curJson); + this.append_response(this.response_extract_stream(curJson, apiEP)); + } + elP.innerText = this.latestResponse; + elP.scrollIntoView(false); + if (done) { + break; + } + } + console.debug("DBUG:SC:PART:Full:", this.latestResponse); + return this.latestResponse; + } + /** + * Handle the oneshot response from server/ai-model + * @param {Response} resp + * @param {string} apiEP + */ + async handle_response_oneshot(resp, apiEP) { + let respBody = await resp.json(); + console.debug(`DBUG:SimpleChat:SC:${this.chatId}:HandleUserSubmit:RespBody:${JSON.stringify(respBody)}`); + return this.response_extract(respBody, apiEP); + } -/** - * Set the class of the children, based on whether it is the idSelected or not. - * @param {HTMLDivElement} elBase - * @param {string} idSelected - * @param {string} classSelected - * @param {string} classUnSelected - */ -function el_children_config_class(elBase, idSelected, classSelected, classUnSelected="") { - for(let child of elBase.children) { - if (child.id == idSelected) { - child.className = classSelected; + /** + * Handle the response from the server be it in oneshot or multipart/stream mode. + * Also take care of the optional garbage trimming. + * @param {Response} resp + * @param {string} apiEP + * @param {HTMLDivElement} elDiv + */ + async handle_response(resp, apiEP, elDiv) { + let theResp = { + assistant: "", + trimmed: "", + } + if (gMe.bStream) { + try { + theResp.assistant = await this.handle_response_multipart(resp, apiEP, elDiv); + this.latestResponse = ""; + } catch (error) { + theResp.assistant = this.latestResponse; + this.add(Roles.Assistant, theResp.assistant); + this.latestResponse = ""; + throw error; + } } else { - child.className = classUnSelected; + theResp.assistant = await this.handle_response_oneshot(resp, apiEP); + } + if (gMe.bTrimGarbage) { + let origMsg = theResp.assistant; + theResp.assistant = du.trim_garbage_at_end(origMsg); + theResp.trimmed = origMsg.substring(theResp.assistant.length); } + this.add(Roles.Assistant, theResp.assistant); + return theResp; } -} -/** - * Create button and set it up. - * @param {string} id - * @param {(this: HTMLButtonElement, ev: MouseEvent) => any} callback - * @param {string | undefined} name - * @param {string | undefined} innerText - */ -function el_create_button(id, callback, name=undefined, innerText=undefined) { - if (!name) { - name = id; - } - if (!innerText) { - innerText = id; - } - let btn = document.createElement("button"); - btn.id = id; - btn.name = name; - btn.innerText = innerText; - btn.addEventListener("click", callback); - return btn; } @@ -302,14 +482,16 @@ class MultiChatUI { this.elDivChat = /** @type{HTMLDivElement} */(document.getElementById("chat-div")); this.elBtnUser = /** @type{HTMLButtonElement} */(document.getElementById("user-btn")); this.elInUser = /** @type{HTMLInputElement} */(document.getElementById("user-in")); - this.elSelectApiEP = /** @type{HTMLSelectElement} */(document.getElementById("api-ep")); + this.elDivHeading = /** @type{HTMLSelectElement} */(document.getElementById("heading")); this.elDivSessions = /** @type{HTMLDivElement} */(document.getElementById("sessions-div")); + this.elBtnSettings = /** @type{HTMLButtonElement} */(document.getElementById("settings")); this.validate_element(this.elInSystem, "system-in"); this.validate_element(this.elDivChat, "chat-div"); this.validate_element(this.elInUser, "user-in"); - this.validate_element(this.elSelectApiEP, "api-ep"); + this.validate_element(this.elDivHeading, "heading"); this.validate_element(this.elDivChat, "sessions-div"); + this.validate_element(this.elBtnSettings, "settings"); } /** @@ -350,13 +532,18 @@ class MultiChatUI { this.handle_session_switch(this.curChatId); } + this.elBtnSettings.addEventListener("click", (ev)=>{ + this.elDivChat.replaceChildren(); + gMe.show_settings(this.elDivChat); + }); + this.elBtnUser.addEventListener("click", (ev)=>{ if (this.elInUser.disabled) { return; } - this.handle_user_submit(this.curChatId, this.elSelectApiEP.value).catch((/** @type{Error} */reason)=>{ + this.handle_user_submit(this.curChatId, gMe.apiEP).catch((/** @type{Error} */reason)=>{ let msg = `ERRR:SimpleChat\nMCUI:HandleUserSubmit:${this.curChatId}\n${reason.name}:${reason.message}`; - console.debug(msg.replace("\n", ":")); + console.error(msg.replace("\n", ":")); alert(msg); this.ui_reset_userinput(); }); @@ -377,6 +564,8 @@ class MultiChatUI { // allow user to insert enter into the system prompt using shift+enter. // while just pressing enter key will lead to setting the system prompt. if ((ev.key === "Enter") && (!ev.shiftKey)) { + let value = this.elInSystem.value; + this.elInSystem.value = value.substring(0,value.length-1); let chat = this.simpleChats[this.curChatId]; chat.add_system_anytime(this.elInSystem.value, this.curChatId); chat.show(this.elDivChat); @@ -392,34 +581,12 @@ class MultiChatUI { * @param {boolean} bSwitchSession */ new_chat_session(chatId, bSwitchSession=false) { - this.simpleChats[chatId] = new SimpleChat(); + this.simpleChats[chatId] = new SimpleChat(chatId); if (bSwitchSession) { this.handle_session_switch(chatId); } } - /** - * Try read json response early, if available. - * @param {Response} resp - */ - async read_json_early(resp) { - if (!resp.body) { - throw Error("ERRR:SimpleChat:MCUI:ReadJsonEarly:No body..."); - } - let tdUtf8 = new TextDecoder("utf-8"); - let rr = resp.body.getReader(); - let gotBody = ""; - while(true) { - let { value: cur, done: done} = await rr.read(); - let curBody = tdUtf8.decode(cur); - console.debug("DBUG:SC:PART:", curBody); - gotBody += curBody; - if (done) { - break; - } - } - return JSON.parse(gotBody); - } /** * Handle user query submit request, wrt specified chat session. @@ -434,7 +601,7 @@ class MultiChatUI { // So if user wants to simulate a multi-chat based completion query, // they will have to enter the full thing, as a suitable multiline // user input/query. - if ((apiEP == ApiEP.Completion) && (gMe.bCompletionFreshChatAlways)) { + if ((apiEP == ApiEP.Type.Completion) && (gMe.bCompletionFreshChatAlways)) { chat.clear(); } @@ -447,41 +614,26 @@ class MultiChatUI { } chat.show(this.elDivChat); - let theBody; - let theUrl = gChatURL[apiEP] - if (apiEP == ApiEP.Chat) { - theBody = chat.request_messages_jsonstr(); - } else { - theBody = chat.request_prompt_jsonstr(gMe.bCompletionInsertStandardRolePrefix); - } + let theUrl = ApiEP.Url(gMe.baseURL, apiEP); + let theBody = chat.request_jsonstr(apiEP); this.elInUser.value = "working..."; this.elInUser.disabled = true; console.debug(`DBUG:SimpleChat:MCUI:${chatId}:HandleUserSubmit:${theUrl}:ReqBody:${theBody}`); + let theHeaders = chat.fetch_headers(apiEP); let resp = await fetch(theUrl, { method: "POST", - headers: { - "Content-Type": "application/json", - }, + headers: theHeaders, body: theBody, }); - let respBody = await resp.json(); - //let respBody = await this.read_json_early(resp); - console.debug(`DBUG:SimpleChat:MCUI:${chatId}:HandleUserSubmit:RespBody:${JSON.stringify(respBody)}`); - let assistantMsg; - if (apiEP == ApiEP.Chat) { - assistantMsg = respBody["choices"][0]["message"]["content"]; - } else { - try { - assistantMsg = respBody["choices"][0]["text"]; - } catch { - assistantMsg = respBody["content"]; - } - } - chat.add(Roles.Assistant, assistantMsg); + let theResp = await chat.handle_response(resp, apiEP, this.elDivChat); if (chatId == this.curChatId) { chat.show(this.elDivChat); + if (theResp.trimmed.length > 0) { + let p = ui.el_create_append_p(`TRIMMED:${theResp.trimmed}`, this.elDivChat); + p.className="role-trim"; + } } else { console.debug(`DBUG:SimpleChat:MCUI:HandleUserSubmit:ChatId has changed:[${chatId}] [${this.curChatId}]`); } @@ -500,7 +652,7 @@ class MultiChatUI { } elDiv.replaceChildren(); // Btn for creating new chat session - let btnNew = el_create_button("New CHAT", (ev)=> { + let btnNew = ui.el_create_button("New CHAT", (ev)=> { if (this.elInUser.disabled) { console.error(`ERRR:SimpleChat:MCUI:NewChat:Current session [${this.curChatId}] awaiting response, ignoring request...`); alert("ERRR:SimpleChat\nMCUI:NewChat\nWait for response to pending query, before starting new chat session"); @@ -514,7 +666,7 @@ class MultiChatUI { } this.new_chat_session(chatIdGot, true); this.create_session_btn(elDiv, chatIdGot); - el_children_config_class(elDiv, chatIdGot, "session-selected", ""); + ui.el_children_config_class(elDiv, chatIdGot, "session-selected", ""); }); elDiv.appendChild(btnNew); // Btns for existing chat sessions @@ -528,7 +680,7 @@ class MultiChatUI { } create_session_btn(elDiv, cid) { - let btn = el_create_button(cid, (ev)=>{ + let btn = ui.el_create_button(cid, (ev)=>{ let target = /** @type{HTMLButtonElement} */(ev.target); console.debug(`DBUG:SimpleChat:MCUI:SessionClick:${target.id}`); if (this.elInUser.disabled) { @@ -537,7 +689,7 @@ class MultiChatUI { return; } this.handle_session_switch(target.id); - el_children_config_class(elDiv, target.id, "session-selected", ""); + ui.el_children_config_class(elDiv, target.id, "session-selected", ""); }); elDiv.appendChild(btn); return btn; @@ -567,46 +719,183 @@ class MultiChatUI { class Me { constructor() { + this.baseURL = "http://127.0.0.1:8080"; this.defaultChatIds = [ "Default", "Other" ]; this.multiChat = new MultiChatUI(); + this.bStream = true; this.bCompletionFreshChatAlways = true; this.bCompletionInsertStandardRolePrefix = false; + this.bTrimGarbage = true; this.iRecentUserMsgCnt = 2; + this.sRecentUserMsgCnt = { + "Full": -1, + "Last0": 1, + "Last1": 2, + "Last2": 3, + "Last4": 5, + }; + this.apiEP = ApiEP.Type.Chat; + this.headers = { + "Content-Type": "application/json", + "Authorization": "", // Authorization: Bearer OPENAI_API_KEY + } // Add needed fields wrt json object to be sent wrt LLM web services completions endpoint. this.chatRequestOptions = { + "model": "gpt-3.5-turbo", "temperature": 0.7, "max_tokens": 1024, - "frequency_penalty": 1.2, - "presence_penalty": 1.2, - "n_predict": 1024 + "n_predict": 1024, + //"frequency_penalty": 1.2, + //"presence_penalty": 1.2, + }; + } + + /** + * Disable console.debug by mapping it to a empty function. + */ + debug_disable() { + this.console_debug = console.debug; + console.debug = () => { + }; } /** + * Setup the load saved chat ui. + * @param {HTMLDivElement} div + * @param {SimpleChat} chat + */ + setup_load(div, chat) { + if (!(chat.ods_key() in localStorage)) { + return; + } + div.innerHTML += `<p class="role-system">Restore</p> + <p>Load previously saved chat session, if available</p>`; + let btn = ui.el_create_button(chat.ods_key(), (ev)=>{ + console.log("DBUG:SimpleChat:SC:Load", chat); + chat.load(); + queueMicrotask(()=>{ + chat.show(div); + this.multiChat.elInSystem.value = chat.get_system_latest(); + }); + }); + div.appendChild(btn); + } + + /** + * Show the configurable parameters info in the passed Div element. * @param {HTMLDivElement} elDiv + * @param {boolean} bAll */ - show_info(elDiv) { + show_info(elDiv, bAll=false) { - var p = document.createElement("p"); - p.innerText = "Settings (devel-tools-console gMe)"; + let p = ui.el_create_append_p("Settings (devel-tools-console document[gMe])", elDiv); p.className = "role-system"; - elDiv.appendChild(p); - var p = document.createElement("p"); - p.innerText = `bCompletionFreshChatAlways:${this.bCompletionFreshChatAlways}`; - elDiv.appendChild(p); + if (bAll) { + + ui.el_create_append_p(`baseURL:${this.baseURL}`, elDiv); + + ui.el_create_append_p(`Authorization:${this.headers["Authorization"]}`, elDiv); + + ui.el_create_append_p(`bStream:${this.bStream}`, elDiv); + + ui.el_create_append_p(`bCompletionFreshChatAlways:${this.bCompletionFreshChatAlways}`, elDiv); + + ui.el_create_append_p(`bCompletionInsertStandardRolePrefix:${this.bCompletionInsertStandardRolePrefix}`, elDiv); + + ui.el_create_append_p(`bTrimGarbage:${this.bTrimGarbage}`, elDiv); + + ui.el_create_append_p(`iRecentUserMsgCnt:${this.iRecentUserMsgCnt}`, elDiv); - p = document.createElement("p"); - p.innerText = `bCompletionInsertStandardRolePrefix:${this.bCompletionInsertStandardRolePrefix}`; - elDiv.appendChild(p); + ui.el_create_append_p(`ApiEndPoint:${this.apiEP}`, elDiv); - p = document.createElement("p"); - p.innerText = `iRecentUserMsgCnt:${this.iRecentUserMsgCnt}`; - elDiv.appendChild(p); + } + + ui.el_create_append_p(`chatRequestOptions:${JSON.stringify(this.chatRequestOptions, null, " - ")}`, elDiv); + ui.el_create_append_p(`headers:${JSON.stringify(this.headers, null, " - ")}`, elDiv); + + } + + /** + * Auto create ui input elements for fields in ChatRequestOptions + * Currently supports text and number field types. + * @param {HTMLDivElement} elDiv + */ + show_settings_chatrequestoptions(elDiv) { + let typeDict = { + "string": "text", + "number": "number", + }; + let fs = document.createElement("fieldset"); + let legend = document.createElement("legend"); + legend.innerText = "ChatRequestOptions"; + fs.appendChild(legend); + elDiv.appendChild(fs); + for(const k in this.chatRequestOptions) { + let val = this.chatRequestOptions[k]; + let type = typeof(val); + if (!((type == "string") || (type == "number"))) { + continue; + } + let inp = ui.el_creatediv_input(`Set${k}`, k, typeDict[type], this.chatRequestOptions[k], (val)=>{ + if (type == "number") { + val = Number(val); + } + this.chatRequestOptions[k] = val; + }); + fs.appendChild(inp.div); + } + } + + /** + * Show settings ui for configurable parameters, in the passed Div element. + * @param {HTMLDivElement} elDiv + */ + show_settings(elDiv) { + + let inp = ui.el_creatediv_input("SetBaseURL", "BaseURL", "text", this.baseURL, (val)=>{ + this.baseURL = val; + }); + elDiv.appendChild(inp.div); + + inp = ui.el_creatediv_input("SetAuthorization", "Authorization", "text", this.headers["Authorization"], (val)=>{ + this.headers["Authorization"] = val; + }); + inp.el.placeholder = "Bearer OPENAI_API_KEY"; + elDiv.appendChild(inp.div); + + let bb = ui.el_creatediv_boolbutton("SetStream", "Stream", {true: "[+] yes stream", false: "[-] do oneshot"}, this.bStream, (val)=>{ + this.bStream = val; + }); + elDiv.appendChild(bb.div); + + bb = ui.el_creatediv_boolbutton("SetCompletionFreshChatAlways", "CompletionFreshChatAlways", {true: "[+] yes fresh", false: "[-] no, with history"}, this.bCompletionFreshChatAlways, (val)=>{ + this.bCompletionFreshChatAlways = val; + }); + elDiv.appendChild(bb.div); + + bb = ui.el_creatediv_boolbutton("SetCompletionInsertStandardRolePrefix", "CompletionInsertStandardRolePrefix", {true: "[+] yes insert", false: "[-] dont insert"}, this.bCompletionInsertStandardRolePrefix, (val)=>{ + this.bCompletionInsertStandardRolePrefix = val; + }); + elDiv.appendChild(bb.div); + + bb = ui.el_creatediv_boolbutton("SetTrimGarbage", "TrimGarbage", {true: "[+] yes trim", false: "[-] dont trim"}, this.bTrimGarbage, (val)=>{ + this.bTrimGarbage = val; + }); + elDiv.appendChild(bb.div); + + let sel = ui.el_creatediv_select("SetChatHistoryInCtxt", "ChatHistoryInCtxt", this.sRecentUserMsgCnt, this.iRecentUserMsgCnt, (val)=>{ + this.iRecentUserMsgCnt = this.sRecentUserMsgCnt[val]; + }); + elDiv.appendChild(sel.div); + + sel = ui.el_creatediv_select("SetApiEP", "ApiEndPoint", ApiEP.Type, this.apiEP, (val)=>{ + this.apiEP = ApiEP.Type[val]; + }); + elDiv.appendChild(sel.div); - p = document.createElement("p"); - p.innerText = `chatRequestOptions:${JSON.stringify(this.chatRequestOptions)}`; - elDiv.appendChild(p); + this.show_settings_chatrequestoptions(elDiv); } @@ -619,6 +908,9 @@ let gMe; function startme() { console.log("INFO:SimpleChat:StartMe:Starting..."); gMe = new Me(); + gMe.debug_disable(); + document["gMe"] = gMe; + document["du"] = du; for (let cid of gMe.defaultChatIds) { gMe.multiChat.new_chat_session(cid); } |