From 2e531d227c5672c169c26251368c925abb775c80 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Mon, 6 Jan 2025 23:20:29 +0100 Subject: Fix invalid escape in requests module Add none auth with OpenAI using nodriver Fix missing 1 required positional argument: 'cls' Update count tokens in GUI Fix streaming example in requests guide Remove ChatGptEs as default model --- g4f/gui/client/static/js/chat.v1.js | 150 ++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 59 deletions(-) (limited to 'g4f/gui/client/static') diff --git a/g4f/gui/client/static/js/chat.v1.js b/g4f/gui/client/static/js/chat.v1.js index fc4b0c5b..cb32f5da 100644 --- a/g4f/gui/client/static/js/chat.v1.js +++ b/g4f/gui/client/static/js/chat.v1.js @@ -34,6 +34,7 @@ let synthesize_storage = {}; let title_storage = {}; let parameters_storage = {}; let finish_storage = {}; +let usage_storage = {}; messageInput.addEventListener("blur", () => { window.scrollTo(0, 0); @@ -60,7 +61,7 @@ if (window.markdownit) { .replaceAll(/|/gm, "") .replaceAll(//gm, "") .replaceAll(/{"bucket_id":"([^"]+)"}/gm, (match, p1) => { - size = appStorage.getItem(`bucket:${p1}`); + size = parseInt(appStorage.getItem(`bucket:${p1}`), 10); return `**Bucket:** [[${p1}]](/backend-api/v2/files/${p1})${size ? ` (${formatFileSize(size)})` : ""}`; }) ) @@ -449,7 +450,7 @@ document.querySelector(".media_player .fa-x").addEventListener("click", ()=>{ media_player.removeChild(audio); }); -const prepare_messages = (messages, message_index = -1, do_continue = false) => { +const prepare_messages = (messages, message_index = -1, do_continue = false, do_filter = true) => { messages = [ ...messages ] if (message_index != null) { // Removes messages after selected @@ -493,7 +494,7 @@ const prepare_messages = (messages, message_index = -1, do_continue = false) => } // Remove history, if it's selected - if (document.getElementById('history')?.checked) { + if (document.getElementById('history')?.checked && do_filter) { if (message_index == null) { messages = [messages.pop(), messages.pop()]; } else { @@ -509,7 +510,7 @@ const prepare_messages = (messages, message_index = -1, do_continue = false) => delete new_message.regenerate; } // Include only not regenerated messages - if (new_message && !new_message.regenerate) { + if (new_message) { // Remove generated images from history if (new_message.content) { new_message.content = filter_message(new_message.content); @@ -518,10 +519,15 @@ const prepare_messages = (messages, message_index = -1, do_continue = false) => delete new_message.provider; delete new_message.synthesize; delete new_message.finish; + delete new_message.usage; delete new_message.conversation; delete new_message.continue; // Append message to new messages - new_messages.push(new_message) + if (do_filter && !new_message.regenerate) { + new_messages.push(new_message) + } else if (!do_filter) { + new_messages.push(new_message) + } } }); @@ -714,6 +720,8 @@ async function add_message_chunk(message, message_id, provider, scroll) { update_message(content_map, message_id, message.login, scroll); } else if (message.type == "finish") { finish_storage[message_id] = message.finish; + } else if (message.type == "usage") { + usage_storage[message_id] = message.usage; } else if (message.type == "parameters") { if (!parameters_storage[provider]) { parameters_storage[provider] = {}; @@ -836,6 +844,7 @@ const ask_gpt = async (message_id, message_index = -1, regenerate = false, provi regenerate, title_storage[message_id], finish_storage[message_id], + usage_storage[message_id], action=="continue" ); delete message_storage[message_id]; @@ -983,6 +992,32 @@ const new_conversation = async () => { say_hello(); }; +function merge_messages(message1, message2) { + let newContent = message2; + if (newContent.startsWith("```")) { + const index = str.indexOf("\n"); + newContent = newContent.substring(index); + } else if (newContent.startsWith("...")) { + newContent = " " + newContent.substring(3); + } + // Remove duplicate words + if (newContent.indexOf(" ") > 0) { + let words = message1.trim().split(" "); + let lastWord = words[words.length - 1]; + if (newContent.startsWith(lastWord)) { + newContent = newContent.substring(lastWord.length); + } + } + // Remove duplicate lines + let lines = message1.trim().split("\n"); + let lastLine = lines[lines.length - 1]; + while (newContent && lastLine && newContent.startsWith(lastLine)) { + newContent = newContent.substring(lastLine.length); + lastLine = lines[lines.length - 1]; + } + return message1 + newContent; +} + const load_conversation = async (conversation_id, scroll=true) => { let conversation = await get_conversation(conversation_id); let messages = conversation?.items || []; @@ -1004,6 +1039,9 @@ const load_conversation = async (conversation_id, scroll=true) => { let last_model = null; let providers = []; let buffer = ""; + let last_usage = null; + let completion_tokens = 0; + messages.forEach((item, i) => { if (item.continue) { elements.pop(); @@ -1011,26 +1049,9 @@ const load_conversation = async (conversation_id, scroll=true) => { buffer = ""; } buffer = buffer.replace(/ \[aborted\]$/g, "").replace(/ \[error\]$/g, ""); - let lines = buffer.trim().split("\n"); - let lastLine = lines[lines.length - 1]; - let newContent = item.content; - if (newContent.startsWith("```")) { - const index = str.indexOf("\n"); - newContent = newContent.substring(index); - } else if (newContent.startsWith("...")) { - newContent = " " + newContent.substring(3); - } - if (newContent.startsWith(lastLine)) { - newContent = newContent.substring(lastLine.length); - } else { - let words = buffer.trim().split(" "); - let lastWord = words[words.length - 1]; - if (newContent.startsWith(lastWord)) { - newContent = newContent.substring(lastWord.length); - } - } - buffer += newContent; + buffer += merge_messages(buffer, item.content); last_model = item.provider?.model; + last_usage = item.usage; providers.push(item.provider?.name); let next_i = parseInt(i) + 1; let next_provider = item.provider ? item.provider : (messages.length > next_i ? messages[next_i].provider : null); @@ -1055,11 +1076,12 @@ const load_conversation = async (conversation_id, scroll=true) => { const objectUrl = URL.createObjectURL(file); let add_buttons = []; - // Add continue button if possible + // Find buttons to add actions = ["variant"] if (item.finish && item.finish.actions) { actions = item.finish.actions } + // Add continue button if possible if (item.role == "assistant" && !actions.includes("continue")) { let reason = "stop"; // Read finish reason from conversation @@ -1071,20 +1093,9 @@ const load_conversation = async (conversation_id, scroll=true) => { // Has a stop or error token at the end if (lastLine.endsWith("[aborted]") || lastLine.endsWith("[error]")) { reason = "error"; - // Has an even number of start or end code tags - } else if (buffer.split("```").length - 1 % 2 === 1) { + // Has an even number of start or end code tags + } else if (reason = "stop" && buffer.split("```").length - 1 % 2 === 1) { reason = "length"; - // Has a end token at the end - } else if (lastLine.endsWith("```") || lastLine.endsWith(".") || lastLine.endsWith("?") || lastLine.endsWith("!") - || lastLine.endsWith('"') || lastLine.endsWith("'") || lastLine.endsWith(")") - || lastLine.endsWith(">") || lastLine.endsWith("]") || lastLine.endsWith("}") ) { - reason = "stop" - } else { - // Has an emoji at the end - const regex = /\p{Emoji}$/u; - if (regex.test(lastLine)) { - reason = "stop" - } } if (reason == "length" || reason == "max_tokens" || reason == "error") { actions.push("continue") @@ -1117,6 +1128,13 @@ const load_conversation = async (conversation_id, scroll=true) => { } } + if (!item.continue) { + completion_tokens = 0; + } + completion_tokens += item.usage?.completion_tokens ? item.usage.completion_tokens : 0; + let next_usage = messages.length > next_i ? messages[next_i].usage : null; + let prompt_tokens = next_usage?.prompt_tokens ? next_usage?.prompt_tokens : 0 + elements.push(`
@@ -1131,7 +1149,7 @@ const load_conversation = async (conversation_id, scroll=true) => { ${provider}
${markdown_render(buffer)}
- ${count_words_and_tokens(buffer, next_provider?.model)} + ${count_words_and_tokens(buffer, next_provider?.model, completion_tokens, prompt_tokens)} ${add_buttons.join("")}
@@ -1140,8 +1158,11 @@ const load_conversation = async (conversation_id, scroll=true) => { }); if (window.GPTTokenizer_cl100k_base) { - const filtered = prepare_messages(messages, null); + const filtered = prepare_messages(messages, null, true, false); if (filtered.length > 0) { + if (GPTTokenizer_o200k_base && last_model?.startsWith("gpt-4o") || last_model?.startsWith("o1")) { + return GPTTokenizer_o200k_base?.encodeChat(filtered, last_model).length; + } last_model = last_model?.startsWith("gpt-3") ? "gpt-3.5-turbo" : "gpt-4" let count_total = GPTTokenizer_cl100k_base?.encodeChat(filtered, last_model).length if (count_total > 0) { @@ -1259,6 +1280,7 @@ const add_message = async ( regenerate = false, title = null, finish = null, + usage = null, do_continue = false ) => { const conversation = await get_conversation(conversation_id); @@ -1287,6 +1309,9 @@ const add_message = async ( if (finish) { new_message.finish = finish; } + if (usage) { + new_message.usage = usage; + } if (do_continue) { new_message.continue = true; } @@ -1493,7 +1518,7 @@ const say_hello = async () => { } } -function count_tokens(model, text) { +function count_tokens(model, text, prompt_tokens = 0) { if (model) { if (window.llamaTokenizer) if (model.startsWith("llama") || model.startsWith("codellama")) { @@ -1504,10 +1529,16 @@ function count_tokens(model, text) { return mistralTokenizer.encode(text).length; } } - if (window.GPTTokenizer_cl100k_base) { - return GPTTokenizer_cl100k_base.encode(text).length; + if (window.GPTTokenizer_cl100k_base && window.GPTTokenizer_o200k_base) { + if (model?.startsWith("gpt-4o") || model?.startsWith("o1")) { + return GPTTokenizer_o200k_base?.encode(text, model).length; + } else { + model = model?.startsWith("gpt-3") ? "gpt-3.5-turbo" : "gpt-4" + return GPTTokenizer_cl100k_base?.encode(text, model).length; + } + } else { + return prompt_tokens; } - return 0; } function count_words(text) { @@ -1518,9 +1549,9 @@ function count_chars(text) { return text.match(/[^\s\p{P}]/gu)?.length || 0; } -function count_words_and_tokens(text, model) { +function count_words_and_tokens(text, model, completion_tokens, prompt_tokens) { text = filter_message(text); - return `(${count_words(text)} words, ${count_chars(text)} chars, ${count_tokens(model, text)} tokens)`; + return `(${count_words(text)} words, ${count_chars(text)} chars, ${completion_tokens ? completion_tokens : count_tokens(model, text, prompt_tokens)} tokens)`; } function update_message(content_map, message_id, content = null, scroll = true) { @@ -1553,16 +1584,12 @@ function update_message(content_map, message_id, content = null, scroll = true) }; let countFocus = messageInput; -let timeoutId; const count_input = async () => { - if (timeoutId) clearTimeout(timeoutId); - timeoutId = setTimeout(() => { - if (countFocus.value) { - inputCount.innerText = count_words_and_tokens(countFocus.value, get_selected_model()?.value); - } else { - inputCount.innerText = ""; - } - }, 100); + if (countFocus.value) { + inputCount.innerText = count_words_and_tokens(countFocus.value, get_selected_model()?.value); + } else { + inputCount.innerText = ""; + } }; messageInput.addEventListener("keyup", count_input); systemPrompt.addEventListener("keyup", count_input); @@ -2115,15 +2142,19 @@ if (SpeechRecognition) { let buffer; let lastDebounceTranscript; recognition.onstart = function() { - microLabel.classList.add("recognition"); startValue = messageInput.value; lastDebounceTranscript = ""; messageInput.readOnly = true; + buffer = ""; }; recognition.onend = function() { messageInput.value = `${startValue ? startValue + "\n" : ""}${buffer}`; - messageInput.readOnly = false; - messageInput.focus(); + if (!microLabel.classList.contains("recognition")) { + recognition.start(); + } else { + messageInput.readOnly = false; + messageInput.focus(); + } }; recognition.onresult = function(event) { if (!event.results) { @@ -2148,10 +2179,11 @@ if (SpeechRecognition) { microLabel.addEventListener("click", (e) => { if (microLabel.classList.contains("recognition")) { + microLabel.classList.remove("recognition"); recognition.stop(); messageInput.value = `${startValue ? startValue + "\n" : ""}${buffer}`; - microLabel.classList.remove("recognition"); } else { + microLabel.classList.add("recognition"); const lang = document.getElementById("recognition-language")?.value; recognition.lang = lang || navigator.language; recognition.start(); -- cgit v1.2.3