summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiner Lohaus <hlohaus@users.noreply.github.com>2024-03-13 05:27:54 +0100
committerHeiner Lohaus <hlohaus@users.noreply.github.com>2024-03-13 05:27:54 +0100
commitecf110e59a35ad41377b82d8d1f5f58802b66539 (patch)
treec3d9da4d4305c14fe01b3fcd77af161b7fb2a9cb
parentAdd count chars to gui, Add retry support to fix rate limit in Bing (diff)
downloadgpt4free-ecf110e59a35ad41377b82d8d1f5f58802b66539.tar
gpt4free-ecf110e59a35ad41377b82d8d1f5f58802b66539.tar.gz
gpt4free-ecf110e59a35ad41377b82d8d1f5f58802b66539.tar.bz2
gpt4free-ecf110e59a35ad41377b82d8d1f5f58802b66539.tar.lz
gpt4free-ecf110e59a35ad41377b82d8d1f5f58802b66539.tar.xz
gpt4free-ecf110e59a35ad41377b82d8d1f5f58802b66539.tar.zst
gpt4free-ecf110e59a35ad41377b82d8d1f5f58802b66539.zip
-rw-r--r--g4f/Provider/Bing.py14
-rw-r--r--g4f/Provider/BingCreateImages.py7
-rw-r--r--g4f/gui/client/js/chat.v1.js47
-rw-r--r--g4f/gui/webview.py24
-rw-r--r--g4f/providers/create_images.py5
5 files changed, 71 insertions, 26 deletions
diff --git a/g4f/Provider/Bing.py b/g4f/Provider/Bing.py
index ca431355..9a067b0f 100644
--- a/g4f/Provider/Bing.py
+++ b/g4f/Provider/Bing.py
@@ -10,13 +10,13 @@ from datetime import datetime
from aiohttp import ClientSession, ClientTimeout, BaseConnector, WSMsgType
from ..typing import AsyncResult, Messages, ImageType, Cookies
-from ..image import ImageResponse, ImageRequest
+from ..image import ImageRequest
from ..errors import ResponseStatusError
from .base_provider import AsyncGeneratorProvider
from .helper import get_connector, get_random_hex
from .bing.upload_image import upload_image
-from .bing.create_images import create_images
from .bing.conversation import Conversation, create_conversation, delete_conversation
+from .BingCreateImages import BingCreateImages
from .. import debug
class Tones:
@@ -71,7 +71,7 @@ class Bing(AsyncGeneratorProvider):
gpt4_turbo = True if model.startswith("gpt-4-turbo") else False
- return stream_generate(prompt, tone, image, context, cookies, get_connector(connector, proxy, True), web_search, gpt4_turbo, timeout)
+ return stream_generate(prompt, tone, image, context, cookies, get_connector(connector, proxy, True), proxy, web_search, gpt4_turbo, timeout)
def create_context(messages: Messages) -> str:
"""
@@ -307,6 +307,7 @@ async def stream_generate(
context: str = None,
cookies: dict = None,
connector: BaseConnector = None,
+ proxy: str = None,
web_search: bool = False,
gpt4_turbo: bool = False,
timeout: int = 900,
@@ -387,8 +388,9 @@ async def stream_generate(
elif message.get('contentType') == "IMAGE":
prompt = message.get('text')
try:
- image_response = ImageResponse(await create_images(session, prompt), prompt, {"preview": "{image}?w=200&h=200"})
- except:
+ image_client = BingCreateImages(cookies, proxy)
+ image_response = await image_client.create_async(prompt)
+ except Exception as e:
response_txt += f"\nhttps://www.bing.com/images/create?q={parse.quote(prompt)}"
do_read = False
if response_txt.startswith(returned_text):
@@ -415,4 +417,4 @@ async def stream_generate(
await asyncio.sleep(sleep_retry)
break
return
- await delete_conversation(session, headers, conversation)
+ await delete_conversation(session, conversation, headers)
diff --git a/g4f/Provider/BingCreateImages.py b/g4f/Provider/BingCreateImages.py
index c465c1d8..f9c4f3b3 100644
--- a/g4f/Provider/BingCreateImages.py
+++ b/g4f/Provider/BingCreateImages.py
@@ -7,14 +7,15 @@ from typing import Iterator, Union
from ..cookies import get_cookies
from ..image import ImageResponse
from ..errors import MissingRequirementsError, MissingAuthError
+from ..typing import Cookies
from .bing.create_images import create_images, create_session, get_cookies_from_browser
class BingCreateImages:
"""A class for creating images using Bing."""
- def __init__(self, cookies: dict[str, str] = {}, proxy: str = None) -> None:
- self.cookies = cookies
- self.proxy = proxy
+ def __init__(self, cookies: Cookies = None, proxy: str = None) -> None:
+ self.cookies: Cookies = cookies
+ self.proxy: str = proxy
def create(self, prompt: str) -> Iterator[Union[ImageResponse, str]]:
"""
diff --git a/g4f/gui/client/js/chat.v1.js b/g4f/gui/client/js/chat.v1.js
index 16b4acb9..d07597ea 100644
--- a/g4f/gui/client/js/chat.v1.js
+++ b/g4f/gui/client/js/chat.v1.js
@@ -27,6 +27,13 @@ messageInput.addEventListener("focus", () => {
document.documentElement.scrollTop = document.documentElement.scrollHeight;
});
+appStorage = window.localStorage || {
+ setItem: (key, value) => self[key] = value,
+ getItem: (key) => self[key],
+ removeItem: (key) => delete self[key],
+ length: 0
+}
+
const markdown_render = (content) => {
return markdown.render(content
.replaceAll(/<!--.+-->/gm, "")
@@ -67,10 +74,10 @@ const register_remove_message = async () => {
}
const delete_conversations = async () => {
- for (let i = 0; i < localStorage.length; i++){
- let key = localStorage.key(i);
+ for (let i = 0; i < appStorage.length; i++){
+ let key = appStorage.key(i);
if (key.startsWith("conversation:")) {
- localStorage.removeItem(key);
+ appStorage.removeItem(key);
}
}
hide_sidebar();
@@ -261,6 +268,7 @@ const ask_gpt = async () => {
body: body
});
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
+ let buffer = ""
while (true) {
const { value, done } = await reader.read();
if (done) break;
@@ -268,7 +276,14 @@ const ask_gpt = async () => {
if (!line) {
continue;
}
- const message = JSON.parse(line);
+ let message;
+ try {
+ message = JSON.parse(buffer + line);
+ buffer = "";
+ } catch {
+ buffer += line
+ continue;
+ }
if (message.type == "content") {
text += message.content;
} else if (message.type == "provider") {
@@ -389,7 +404,7 @@ const hide_option = async (conversation_id) => {
};
const delete_conversation = async (conversation_id) => {
- localStorage.removeItem(`conversation:${conversation_id}`);
+ appStorage.removeItem(`conversation:${conversation_id}`);
const conversation = document.getElementById(`convo-${conversation_id}`);
conversation.remove();
@@ -491,13 +506,13 @@ const load_conversation = async (conversation_id, scroll = true) => {
async function get_conversation(conversation_id) {
let conversation = await JSON.parse(
- localStorage.getItem(`conversation:${conversation_id}`)
+ appStorage.getItem(`conversation:${conversation_id}`)
);
return conversation;
}
async function save_conversation(conversation_id, conversation) {
- localStorage.setItem(
+ appStorage.setItem(
`conversation:${conversation_id}`,
JSON.stringify(conversation)
);
@@ -515,7 +530,7 @@ async function add_conversation(conversation_id, content) {
title = content + '&nbsp;'.repeat(19 - content.length)
}
- if (localStorage.getItem(`conversation:${conversation_id}`) == null) {
+ if (appStorage.getItem(`conversation:${conversation_id}`) == null) {
await save_conversation(conversation_id, {
id: conversation_id,
title: title,
@@ -577,9 +592,9 @@ const add_message = async (conversation_id, role, content, provider) => {
const load_conversations = async () => {
let conversations = [];
- for (let i = 0; i < localStorage.length; i++) {
- if (localStorage.key(i).startsWith("conversation:")) {
- let conversation = localStorage.getItem(localStorage.key(i));
+ for (let i = 0; i < appStorage.length; i++) {
+ if (appStorage.key(i).startsWith("conversation:")) {
+ let conversation = appStorage.getItem(appStorage.key(i));
conversations.push(JSON.parse(conversation));
}
}
@@ -657,10 +672,10 @@ const register_settings_localstorage = async () => {
element.addEventListener('change', async (event) => {
switch (event.target.type) {
case "checkbox":
- localStorage.setItem(id, event.target.checked);
+ appStorage.setItem(id, event.target.checked);
break;
case "select-one":
- localStorage.setItem(id, event.target.selectedIndex);
+ appStorage.setItem(id, event.target.selectedIndex);
break;
default:
console.warn("Unresolved element type");
@@ -672,7 +687,7 @@ const register_settings_localstorage = async () => {
const load_settings_localstorage = async () => {
for (id of ["switch", "model", "jailbreak", "patch", "provider", "history"]) {
element = document.getElementById(id);
- value = localStorage.getItem(element.id);
+ value = appStorage.getItem(element.id);
if (value) {
switch (element.type) {
case "checkbox":
@@ -712,12 +727,12 @@ const say_hello = async () => {
// Theme storage for recurring viewers
const storeTheme = function (theme) {
- localStorage.setItem("theme", theme);
+ appStorage.setItem("theme", theme);
};
// set theme when visitor returns
const setTheme = function () {
- const activeTheme = localStorage.getItem("theme");
+ const activeTheme = appStorage.getItem("theme");
colorThemes.forEach((themeOption) => {
if (themeOption.id === activeTheme) {
themeOption.checked = true;
diff --git a/g4f/gui/webview.py b/g4f/gui/webview.py
new file mode 100644
index 00000000..5a4263dc
--- /dev/null
+++ b/g4f/gui/webview.py
@@ -0,0 +1,24 @@
+import webview
+from functools import partial
+from platformdirs import user_config_dir
+
+from g4f.gui import run_gui
+from g4f.gui.run import gui_parser
+import g4f.version
+import g4f.debug
+
+def run_webview(host: str = "0.0.0.0", port: int = 8080, debug: bool = True):
+ webview.create_window(f"g4f - {g4f.version.utils.current_version}", f"http://{host}:{port}/")
+ if debug:
+ g4f.debug.logging = True
+ webview.start(
+ partial(run_gui, host, port),
+ private_mode=False,
+ storage_path=user_config_dir("g4f-webview"),
+ debug=debug
+ )
+
+if __name__ == "__main__":
+ parser = gui_parser()
+ args = parser.parse_args()
+ run_webview(args.host, args.port, args.debug) \ No newline at end of file
diff --git a/g4f/providers/create_images.py b/g4f/providers/create_images.py
index 29a2a041..29db9435 100644
--- a/g4f/providers/create_images.py
+++ b/g4f/providers/create_images.py
@@ -6,6 +6,7 @@ import asyncio
from .. import debug
from ..typing import CreateResult, Messages
from .types import BaseProvider, ProviderType
+from ..image import ImageResponse
system_message = """
You can generate images, pictures, photos or img with the DALL-E 3 image generator.
@@ -92,7 +93,9 @@ class CreateImagesProvider(BaseProvider):
messages.insert(0, {"role": "system", "content": self.system_message})
buffer = ""
for chunk in self.provider.create_completion(model, messages, stream, **kwargs):
- if isinstance(chunk, str) and buffer or "<" in chunk:
+ if isinstance(chunk, ImageResponse):
+ yield chunk
+ elif isinstance(chunk, str) and buffer or "<" in chunk:
buffer += chunk
if ">" in buffer:
match = re.search(r'<img data-prompt="(.*?)">', buffer)