From 335c971f6a9cd071d18f9fffeb76df4eda8876d5 Mon Sep 17 00:00:00 2001 From: H Lohaus Date: Fri, 13 Dec 2024 22:20:58 +0100 Subject: Add multiple images support (#2478) * Add multiple images support * Add multiple images support in gui * Support multiple images in legacy client and in the api Fix some model names in provider model list * Fix unittests * Add vision and providers docs --- g4f/gui/client/static/js/chat.v1.js | 46 +++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 17 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 0cde4188..044d2ab7 100644 --- a/g4f/gui/client/static/js/chat.v1.js +++ b/g4f/gui/client/static/js/chat.v1.js @@ -343,11 +343,18 @@ const handle_ask = async () => { let message_index = await add_message(window.conversation_id, "user", message); let message_id = get_message_id(); - if (imageInput.dataset.src) URL.revokeObjectURL(imageInput.dataset.src); + if (imageInput.dataset.objects) { + imageInput.dataset.objects.split(" ").forEach((object)=>URL.revokeObjectURL(object)) + delete imageInput.dataset.objects; + } const input = imageInput && imageInput.files.length > 0 ? imageInput : cameraInput - if (input.files.length > 0) imageInput.dataset.src = URL.createObjectURL(input.files[0]); - else delete imageInput.dataset.src - + images = []; + if (input.files.length > 0) { + for (const file of input.files) { + images.push(URL.createObjectURL(file)); + } + imageInput.dataset.objects = images.join(" "); + } message_box.innerHTML += `
@@ -358,10 +365,7 @@ const handle_ask = async () => {
${markdown_render(message)} - ${imageInput.dataset.src - ? 'Image upload' - : '' - } + ${images.map((object)=>'Image upload').join("")}
${count_words_and_tokens(message, get_selected_model()?.value)} @@ -602,7 +606,7 @@ const ask_gpt = async (message_id, message_index = -1, regenerate = false, provi } try { const input = imageInput && imageInput.files.length > 0 ? imageInput : cameraInput; - const file = input && input.files.length > 0 ? input.files[0] : null; + const files = input && input.files.length > 0 ? input.files : null; const auto_continue = document.getElementById("auto_continue")?.checked; const download_images = document.getElementById("download_images")?.checked; let api_key = get_api_key_by_provider(provider); @@ -616,7 +620,7 @@ const ask_gpt = async (message_id, message_index = -1, regenerate = false, provi auto_continue: auto_continue, download_images: download_images, api_key: api_key, - }, file, message_id); + }, files, message_id); if (!error_storage[message_id]) { html = markdown_render(message_storage[message_id]); content_map.inner.innerHTML = html; @@ -771,6 +775,7 @@ const set_conversation = async (conversation_id) => { const new_conversation = async () => { history.pushState({}, null, `/chat/`); window.conversation_id = uuid(); + document.title = window.title || document.title; await clear_conversation(); if (systemPrompt) { @@ -790,6 +795,8 @@ const load_conversation = async (conversation_id, scroll=true) => { return; } + document.title = conversation.new_title ? `g4f - ${conversation.new_title}` : document.title; + if (systemPrompt) { systemPrompt.value = conversation.system || ""; } @@ -1422,7 +1429,10 @@ async function load_version() { let new_version = document.querySelector(".new_version"); if (new_version) return; const versions = await api("version"); - document.title = 'g4f - ' + versions["version"]; + window.title = 'g4f - ' + versions["version"]; + if (document.title == "g4f - gui") { + document.title = window.title; + } let text = "version ~ " if (versions["version"] != versions["latest_version"]) { let release_url = 'https://github.com/xtekky/gpt4free/releases/latest'; @@ -1445,9 +1455,9 @@ setTimeout(load_version, 100); [imageInput, cameraInput].forEach((el) => { el.addEventListener('click', async () => { el.value = ''; - if (imageInput.dataset.src) { - URL.revokeObjectURL(imageInput.dataset.src); - delete imageInput.dataset.src + if (imageInput.dataset.objects) { + imageInput.dataset.objects.split(" ").forEach((object) => URL.revokeObjectURL(object)); + delete imageInput.dataset.objects } }); }); @@ -1521,7 +1531,7 @@ function get_selected_model() { } } -async function api(ressource, args=null, file=null, message_id=null) { +async function api(ressource, args=null, files=null, message_id=null) { let api_key; if (ressource == "models" && args) { api_key = get_api_key_by_provider(args); @@ -1535,9 +1545,11 @@ async function api(ressource, args=null, file=null, message_id=null) { if (ressource == "conversation") { let body = JSON.stringify(args); headers.accept = 'text/event-stream'; - if (file !== null) { + if (files !== null) { const formData = new FormData(); - formData.append('file', file); + for (const file of files) { + formData.append('files[]', file) + } formData.append('json', body); body = formData; } else { -- cgit v1.2.3