From 486e43dabd1198e6f3c94a4040fc01f5b2fe824c Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Tue, 19 Mar 2024 18:48:32 +0100 Subject: Fix missing websocket_request_id in OpenaiChat Add RateLimitErrors to Bing Add android support to gui api Add annotations import to gui api --- g4f/gui/server/api.py | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) (limited to 'g4f/gui/server/api.py') diff --git a/g4f/gui/server/api.py b/g4f/gui/server/api.py index 4dfc43d4..43bb4250 100644 --- a/g4f/gui/server/api.py +++ b/g4f/gui/server/api.py @@ -1,11 +1,40 @@ +from __future__ import annotations + import logging import json +import os.path from typing import Iterator +from uuid import uuid4 +from functools import partial try: import webview + import platformdirs except ImportError: ... +try: + from plyer import camera + from plyer import filechooser + has_plyer = True +except ImportError: + has_plyer = False +try: + from android.runnable import run_on_ui_thread + from android.storage import app_storage_path + from android.permissions import request_permissions, Permission + from android.permissions import _RequestPermissionsManager + _RequestPermissionsManager.register_callback() + from .android_gallery import user_select_image + has_android = True +except ImportError: + run_on_ui_thread = lambda a : a + app_storage_path = platformdirs.user_pictures_dir + user_select_image = partial( + filechooser.open_file, + path=platformdirs.user_pictures_dir(), + filters=[["Image", "*.jpg", "*.jpeg", "*.png", "*.webp", "*.svg"]], + ) + has_android = False from g4f import version, models from g4f import get_last_provider, ChatCompletion @@ -75,13 +104,71 @@ class Api(): return {'title': ''} def get_conversation(self, options: dict, **kwargs) -> Iterator: - window = webview.active_window() + window = webview.windows[0] + if hasattr(self, "image") and self.image is not None: + kwargs["image"] = open(self.image, "rb") for message in self._create_response_stream( self._prepare_conversation_kwargs(options, kwargs), options.get("conversation_id") ): if not window.evaluate_js(f"if (!this.abort) this.add_message_chunk({json.dumps(message)}); !this.abort && !this.error;"): break + self.image = None + self.set_selected(None) + + @run_on_ui_thread + def choose_file(self): + self.request_permissions() + filechooser.open_file( + path=platformdirs.user_pictures_dir(), + on_selection=print + ) + + @run_on_ui_thread + def choose_image(self): + self.request_permissions() + user_select_image( + on_selection=self.on_image_selection + ) + + @run_on_ui_thread + def take_picture(self): + self.request_permissions() + filename = os.path.join(app_storage_path(), f"chat-{uuid4()}.png") + camera.take_picture(filename=filename, on_complete=self.on_camera) + + def on_image_selection(self, filename): + if filename is not None and os.path.exists(filename): + self.image = filename + else: + self.image = None + self.set_selected(None if self.image is None else "image") + + def on_camera(self, filename): + if filename is not None and os.path.exists(filename): + self.image = filename + else: + self.image = None + self.set_selected(None if self.image is None else "camera") + + def set_selected(self, input_id: str = None): + window = webview.windows[0] + if window is not None: + window.evaluate_js( + f"document.querySelector(`.file-label.selected`)?.classList.remove(`selected`);" + ) + if input_id is not None and input_id in ("image", "camera"): + window.evaluate_js( + f'document.querySelector(`label[for="{input_id}"]`)?.classList.add(`selected`);' + ) + + def request_permissions(self): + if has_android: + request_permissions([ + Permission.CAMERA, + Permission.READ_EXTERNAL_STORAGE, + Permission.WRITE_EXTERNAL_STORAGE + ]) def _prepare_conversation_kwargs(self, json_data: dict, kwargs: dict): """ -- cgit v1.2.3