From 307c8f53e74f1668282a6842ee0de672857b49fa Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Sun, 25 Feb 2024 09:41:39 +0100 Subject: Custom api_base for GeminiPro --- g4f/Provider/GeminiPro.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/g4f/Provider/GeminiPro.py b/g4f/Provider/GeminiPro.py index e1738dc8..792cd5d1 100644 --- a/g4f/Provider/GeminiPro.py +++ b/g4f/Provider/GeminiPro.py @@ -13,6 +13,7 @@ class GeminiPro(AsyncGeneratorProvider, ProviderModelMixin): url = "https://ai.google.dev" working = True supports_message_history = True + needs_auth = True default_model = "gemini-pro" models = ["gemini-pro", "gemini-pro-vision"] @@ -24,19 +25,24 @@ class GeminiPro(AsyncGeneratorProvider, ProviderModelMixin): stream: bool = False, proxy: str = None, api_key: str = None, + api_base: str = None, image: ImageType = None, **kwargs ) -> AsyncResult: model = "gemini-pro-vision" if not model and image else model model = cls.get_model(model) - if not api_key: - raise MissingAuthError('Missing "api_key" for auth') - headers = { - "Content-Type": "application/json", - } - async with ClientSession(headers=headers) as session: - method = "streamGenerateContent" if stream else "generateContent" - url = f"https://generativelanguage.googleapis.com/v1beta/models/{model}:{method}" + + if not api_key and not api_base: + raise MissingAuthError('Missing "api_key" or "api_base"') + if not api_base: + api_base = f"https://generativelanguage.googleapis.com/v1beta" + + method = "streamGenerateContent" if stream else "generateContent" + url = f"{api_base.rstrip('/')}/models/{model}:{method}" + if api_key: + url += f"?key={api_key}" + + async with ClientSession() as session: contents = [ { "role": "model" if message["role"] == "assistant" else message["role"], @@ -62,7 +68,7 @@ class GeminiPro(AsyncGeneratorProvider, ProviderModelMixin): "topK": kwargs.get("top_k"), } } - async with session.post(url, params={"key": api_key}, json=data, proxy=proxy) as response: + async with session.post(url, json=data, proxy=proxy) as response: if not response.ok: data = await response.json() raise RuntimeError(data[0]["error"]["message"]) @@ -78,7 +84,7 @@ class GeminiPro(AsyncGeneratorProvider, ProviderModelMixin): yield data["candidates"][0]["content"]["parts"][0]["text"] except: data = data.decode() if isinstance(data, bytes) else data - raise RuntimeError(f"Read text failed. data: {data}") + raise RuntimeError(f"Read chunk failed. data: {data}") lines = [] else: lines.append(chunk) -- cgit v1.2.3 From 84b3a19c9de9168f9eaf769f63e19d30c66f3ddd Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Sun, 25 Feb 2024 10:03:27 +0100 Subject: Improve show result in gui --- g4f/gui/client/js/chat.v1.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/g4f/gui/client/js/chat.v1.js b/g4f/gui/client/js/chat.v1.js index 9585ca98..e5b2d653 100644 --- a/g4f/gui/client/js/chat.v1.js +++ b/g4f/gui/client/js/chat.v1.js @@ -268,6 +268,11 @@ const ask_gpt = async () => { } } if (!error) { + // Remove cursor + html = markdown_render(text); + content_inner.innerHTML = html; + highlight(content_inner); + if (imageInput) imageInput.value = ""; if (cameraInput) cameraInput.value = ""; if (fileInput) fileInput.value = ""; @@ -275,20 +280,19 @@ const ask_gpt = async () => { } catch (e) { console.error(e); - if (e.name != `AbortError`) { - text = `oops ! something went wrong, please try again / reload. [stacktrace in console]`; + if (e.name != "AbortError") { + error = true; + text = "oops ! something went wrong, please try again / reload. [stacktrace in console]"; content_inner.innerHTML = text; } else { content_inner.innerHTML += ` [aborted]`; text += ` [aborted]` } } - let cursorDiv = document.getElementById(`cursor`); - if (cursorDiv) cursorDiv.parentNode.removeChild(cursorDiv); - if (text) { + if (!error) { await add_message(window.conversation_id, "assistant", text, provider); + await load_conversation(window.conversation_id); } - await load_conversation(window.conversation_id); message_box.scrollTop = message_box.scrollHeight; await remove_cancel_button(); await register_remove_message(); -- cgit v1.2.3 From b4b74c991be143c701795836cfc9fce56da4a497 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Sun, 25 Feb 2024 15:48:03 +0100 Subject: gui: remove cursor on errors Add auth header to GeminiPro provider --- g4f/Provider/GeminiPro.py | 16 +++++++++------- g4f/Provider/Liaobots.py | 2 +- g4f/gui/client/js/chat.v1.js | 37 ++++++++++++++++++++----------------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/g4f/Provider/GeminiPro.py b/g4f/Provider/GeminiPro.py index 792cd5d1..87ded3ac 100644 --- a/g4f/Provider/GeminiPro.py +++ b/g4f/Provider/GeminiPro.py @@ -32,17 +32,20 @@ class GeminiPro(AsyncGeneratorProvider, ProviderModelMixin): model = "gemini-pro-vision" if not model and image else model model = cls.get_model(model) - if not api_key and not api_base: - raise MissingAuthError('Missing "api_key" or "api_base"') + if not api_key: + raise MissingAuthError('Missing "api_key"') if not api_base: api_base = f"https://generativelanguage.googleapis.com/v1beta" method = "streamGenerateContent" if stream else "generateContent" url = f"{api_base.rstrip('/')}/models/{model}:{method}" - if api_key: + headers = None + if api_base: + headers = {f"Authorization": "Bearer {api_key}"} + else: url += f"?key={api_key}" - async with ClientSession() as session: + async with ClientSession(headers=headers) as session: contents = [ { "role": "model" if message["role"] == "assistant" else message["role"], @@ -79,12 +82,11 @@ class GeminiPro(AsyncGeneratorProvider, ProviderModelMixin): lines = [b"{\n"] elif chunk == b",\r\n" or chunk == b"]": try: - data = b"".join(lines) - data = json.loads(data) + data = json.loads(b"".join(lines)) yield data["candidates"][0]["content"]["parts"][0]["text"] except: data = data.decode() if isinstance(data, bytes) else data - raise RuntimeError(f"Read chunk failed. data: {data}") + raise RuntimeError(f"Read chunk failed: {data}") lines = [] else: lines.append(chunk) diff --git a/g4f/Provider/Liaobots.py b/g4f/Provider/Liaobots.py index e93642ba..54bf7f2e 100644 --- a/g4f/Provider/Liaobots.py +++ b/g4f/Provider/Liaobots.py @@ -78,7 +78,7 @@ class Liaobots(AsyncGeneratorProvider, ProviderModelMixin): supports_gpt_35_turbo = True supports_gpt_4 = True default_model = "gpt-3.5-turbo" - models = [m for m in models] + models = list(models) model_aliases = { "claude-v2": "claude-2" } diff --git a/g4f/gui/client/js/chat.v1.js b/g4f/gui/client/js/chat.v1.js index e5b2d653..c727dbf9 100644 --- a/g4f/gui/client/js/chat.v1.js +++ b/g4f/gui/client/js/chat.v1.js @@ -3,7 +3,6 @@ const markdown = window.markdownit(); const message_box = document.getElementById(`messages`); const message_input = document.getElementById(`message-input`); const box_conversations = document.querySelector(`.top`); -const spinner = box_conversations.querySelector(".spinner"); const stop_generating = document.querySelector(`.stop_generating`); const regenerate = document.querySelector(`.regenerate`); const send_button = document.querySelector(`#send-button`); @@ -71,6 +70,7 @@ const handle_ask = async () => { message_input.style.height = `82px`; message_input.focus(); window.scrollTo(0, 0); + message = message_input.value if (message.length > 0) { message_input.value = ''; @@ -292,13 +292,16 @@ const ask_gpt = async () => { if (!error) { await add_message(window.conversation_id, "assistant", text, provider); await load_conversation(window.conversation_id); + } else { + let cursorDiv = document.getElementById(`cursor`); + if (cursorDiv) cursorDiv.parentNode.removeChild(cursorDiv); } message_box.scrollTop = message_box.scrollHeight; await remove_cancel_button(); await register_remove_message(); prompt_lock = false; window.scrollTo(0, 0); - await load_conversations(20, 0); + await load_conversations(); regenerate.classList.remove(`regenerate-hidden`); }; @@ -357,7 +360,7 @@ const delete_conversation = async (conversation_id) => { await new_conversation(); } - await load_conversations(20, 0, true); + await load_conversations(); }; const set_conversation = async (conversation_id) => { @@ -366,7 +369,7 @@ const set_conversation = async (conversation_id) => { await clear_conversation(); await load_conversation(conversation_id); - await load_conversations(20, 0, true); + await load_conversations(); }; const new_conversation = async () => { @@ -374,7 +377,7 @@ const new_conversation = async () => { window.conversation_id = uuid(); await clear_conversation(); - await load_conversations(20, 0, true); + await load_conversations(); await say_hello() }; @@ -439,14 +442,14 @@ function count_words(text) { } function count_tokens(model, text) { - if (model.startsWith("gpt-3") || model.startsWith("gpt-4")) { - return GPTTokenizer_cl100k_base?.encode(text).length + if (model.startsWith("gpt-3") || model.startsWith("gpt-4") || model.startsWith("text-davinci")) { + return GPTTokenizer_cl100k_base?.encode(text).length; } if (model.startsWith("llama2") || model.startsWith("codellama")) { - return llamaTokenizer?.encode(text).length + return llamaTokenizer?.encode(text).length; } if (model.startsWith("mistral") || model.startsWith("mixtral")) { - return mistralTokenizer?.encode(text).length + return mistralTokenizer?.encode(text).length; } } @@ -530,7 +533,7 @@ const add_message = async (conversation_id, role, content, provider) => { return conversation.items.length - 1; }; -const load_conversations = async (limit, offset, loader) => { +const load_conversations = async () => { let conversations = []; for (let i = 0; i < localStorage.length; i++) { if (localStorage.key(i).startsWith("conversation:")) { @@ -554,7 +557,6 @@ const load_conversations = async (limit, offset, loader) => { `; } - }; document.getElementById(`cancelButton`).addEventListener(`click`, async () => { @@ -697,10 +699,8 @@ window.onload = async () => { } } - if (conversations == 0) localStorage.clear(); - await setTimeout(() => { - load_conversations(20, 0); + load_conversations(); }, 1); if (/\/chat\/.+/.test(window.location.href)) { @@ -780,15 +780,17 @@ observer.observe(message_input, { attributes: true }); versions = await response.json() document.title = 'g4f - gui - ' + versions["version"]; - text = "version ~ " + let text = "version ~ " if (versions["version"] != versions["latest_version"]) { - release_url = 'https://github.com/xtekky/gpt4free/releases/tag/' + versions["latest_version"]; - text += '' + versions["version"] + ' 🆕'; + let release_url = 'https://github.com/xtekky/gpt4free/releases/tag/' + versions["latest_version"]; + let title = `New version: ${versions["latest_version"]}`; + text += `${versions["version"]} 🆕`; } else { text += versions["version"]; } document.getElementById("version_text").innerHTML = text })() + for (const el of [imageInput, cameraInput]) { el.addEventListener('click', async () => { el.value = ''; @@ -798,6 +800,7 @@ for (const el of [imageInput, cameraInput]) { } }); } + fileInput.addEventListener('click', async (event) => { fileInput.value = ''; delete fileInput.dataset.text; -- cgit v1.2.3 From 12464bfac01af74e17c40b41462490cedcb3f480 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Sun, 25 Feb 2024 21:31:52 +0100 Subject: Improve mobile css styles --- g4f/gui/client/css/style.css | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/g4f/gui/client/css/style.css b/g4f/gui/client/css/style.css index bd42280d..bed54f88 100644 --- a/g4f/gui/client/css/style.css +++ b/g4f/gui/client/css/style.css @@ -541,7 +541,6 @@ label[for="camera"] { display: flex; align-items: center; gap: 16px; - padding-right: 15px } .field .about { @@ -569,7 +568,16 @@ select { padding: 8px 16px; appearance: none; - width: 250px; + width: 160px; +} + +@media only screen and (min-width: 40em) { + select { + width: 200px; + } + .field { + padding-right: 15px + } } .input-box { -- cgit v1.2.3