diff options
-rw-r--r-- | g4f/Provider/Ai4Chat.py | 3 | ||||
-rw-r--r-- | g4f/Provider/Mhystical.py | 6 | ||||
-rw-r--r-- | g4f/Provider/you/har_file.py | 8 | ||||
-rw-r--r-- | g4f/__init__.py | 9 | ||||
-rw-r--r-- | g4f/api/__init__.py | 8 | ||||
-rw-r--r-- | g4f/api/_logging.py | 36 | ||||
-rw-r--r-- | g4f/gui/server/api.py | 6 | ||||
-rw-r--r-- | g4f/image.py | 11 | ||||
-rw-r--r-- | g4f/providers/base_provider.py | 2 | ||||
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | setup.py | 2 |
11 files changed, 56 insertions, 36 deletions
diff --git a/g4f/Provider/Ai4Chat.py b/g4f/Provider/Ai4Chat.py index 9f9874bb..56b47e5c 100644 --- a/g4f/Provider/Ai4Chat.py +++ b/g4f/Provider/Ai4Chat.py @@ -9,6 +9,7 @@ from ..typing import AsyncResult, Messages from .base_provider import AsyncGeneratorProvider, ProviderModelMixin from .helper import format_prompt +logger = logging.getLogger(__name__) class Ai4Chat(AsyncGeneratorProvider, ProviderModelMixin): label = "AI4Chat" @@ -84,5 +85,5 @@ class Ai4Chat(AsyncGeneratorProvider, ProviderModelMixin): yield clean_message except Exception as e: - logging.exception("Error while calling AI 4Chat API: %s", e) + logger.exception("Error while calling AI 4Chat API: %s", e) yield f"Error: {e}" diff --git a/g4f/Provider/Mhystical.py b/g4f/Provider/Mhystical.py index 44b32604..2aa98ebc 100644 --- a/g4f/Provider/Mhystical.py +++ b/g4f/Provider/Mhystical.py @@ -18,6 +18,8 @@ from .helper import format_prompt """ +logger = logging.getLogger(__name__) + class Mhystical(AsyncGeneratorProvider, ProviderModelMixin): url = "https://api.mhystical.cc" api_endpoint = "https://api.mhystical.cc/v1/completions" @@ -84,5 +86,5 @@ class Mhystical(AsyncGeneratorProvider, ProviderModelMixin): message_content = json_response["choices"][0]["message"]["content"] return message_content except (KeyError, IndexError, json.JSONDecodeError) as e: - logging.error("Error parsing response: %s", e) - return "Error: Failed to parse response from API."
\ No newline at end of file + logger.error("Error parsing response: %s", e) + return "Error: Failed to parse response from API." diff --git a/g4f/Provider/you/har_file.py b/g4f/Provider/you/har_file.py index 71d741fd..40bf3882 100644 --- a/g4f/Provider/you/har_file.py +++ b/g4f/Provider/you/har_file.py @@ -11,7 +11,7 @@ from ...cookies import get_cookies_dir from ...errors import MissingRequirementsError from ... import debug -logging.basicConfig(level=logging.ERROR) +logger = logging.getLogger(__name__) class NoValidHarFileError(Exception): ... @@ -81,14 +81,14 @@ async def get_telemetry_ids(proxy: str = None) -> list: return [await create_telemetry_id(proxy)] except NoValidHarFileError as e: if debug.logging: - logging.error(e) + logger.error(e) try: from nodriver import start except ImportError: raise MissingRequirementsError('Add .har file from you.com or install "nodriver" package | pip install -U nodriver') if debug.logging: - logging.error('Getting telemetry_id for you.com with nodriver') + logger.error('Getting telemetry_id for you.com with nodriver') browser = page = None try: @@ -112,4 +112,4 @@ async def get_telemetry_ids(proxy: str = None) -> list: await browser.stop() except Exception as e: if debug.logging: - logging.error(e) + logger.error(e) diff --git a/g4f/__init__.py b/g4f/__init__.py index d77fe760..f59a1446 100644 --- a/g4f/__init__.py +++ b/g4f/__init__.py @@ -1,6 +1,7 @@ from __future__ import annotations import os +import logging from . import debug, version from .models import Model @@ -12,6 +13,14 @@ from .providers.types import ProviderType from .providers.base_provider import AsyncGeneratorProvider from .client.service import get_model_and_provider, get_last_provider +#Configure "g4f" logger +logger = logging.getLogger(__name__) +log_handler = logging.StreamHandler() +log_handler.setFormatter(logging.Formatter(logging.BASIC_FORMAT)) +logger.addHandler(log_handler) + +logger.setLevel(logging.ERROR) + class ChatCompletion: @staticmethod def create(model : Union[Model, str], diff --git a/g4f/api/__init__.py b/g4f/api/__init__.py index b9591b20..e7f87260 100644 --- a/g4f/api/__init__.py +++ b/g4f/api/__init__.py @@ -22,6 +22,8 @@ from g4f.client import Client, ChatCompletion, ChatCompletionChunk, ImagesRespon from g4f.typing import Messages from g4f.cookies import read_cookie_files +logger = logging.getLogger(__name__) + def create_app(g4f_api_key: str = None): app = FastAPI() @@ -204,14 +206,14 @@ class Api: except GeneratorExit: pass except Exception as e: - logging.exception(e) + logger.exception(e) yield f'data: {format_exception(e, config)}\n\n' yield "data: [DONE]\n\n" return StreamingResponse(streaming(), media_type="text/event-stream") except Exception as e: - logging.exception(e) + logger.exception(e) return Response(content=format_exception(e, config), status_code=500, media_type="application/json") @self.app.post("/v1/images/generate") @@ -226,7 +228,7 @@ class Api: response_data = [{"url": image.url, "b64_json": image.b64_json} for image in response.data] return JSONResponse({"data": response_data}) except Exception as e: - logging.exception(e) + logger.exception(e) return Response(content=format_exception(e, config), status_code=500, media_type="application/json") @self.app.post("/v1/completions") diff --git a/g4f/api/_logging.py b/g4f/api/_logging.py index e91dff76..884d7529 100644 --- a/g4f/api/_logging.py +++ b/g4f/api/_logging.py @@ -1,6 +1,6 @@ import sys,logging -from loguru import logger +#from loguru import logger def __exception_handle(e_type, e_value, e_traceback): if issubclass(e_type, KeyboardInterrupt): @@ -9,24 +9,24 @@ def __exception_handle(e_type, e_value, e_traceback): sys.__excepthook__(e_type, e_value, e_traceback) -class __InterceptHandler(logging.Handler): - def emit(self, record): - try: - level = logger.level(record.levelname).name - except ValueError: - level = record.levelno - - frame, depth = logging.currentframe(), 2 - while frame.f_code.co_filename == logging.__file__: - frame = frame.f_back - depth += 1 - - logger.opt(depth=depth, exception=record.exc_info).log( - level, record.getMessage() - ) +#class __InterceptHandler(logging.Handler): +# def emit(self, record): +# try: +# level = logger.level(record.levelname).name +# except ValueError: +# level = record.levelno +# +# frame, depth = logging.currentframe(), 2 +# while frame.f_code.co_filename == logging.__file__: +# frame = frame.f_back +# depth += 1 + +# logger.opt(depth=depth, exception=record.exc_info).log( +# level, record.getMessage() +# ) def hook_except_handle(): sys.excepthook = __exception_handle -def hook_logging(**kwargs): - logging.basicConfig(handlers=[__InterceptHandler()], **kwargs) +#def hook_logging(**kwargs): +# logging.basicConfig(handlers=[__InterceptHandler()], **kwargs) diff --git a/g4f/gui/server/api.py b/g4f/gui/server/api.py index 7aac650a..dafcb5d4 100644 --- a/g4f/gui/server/api.py +++ b/g4f/gui/server/api.py @@ -19,6 +19,8 @@ from g4f.Provider import ProviderType, __providers__, __map__ from g4f.providers.base_provider import ProviderModelMixin, FinishReason from g4f.providers.conversation import BaseConversation +logger = logging.getLogger(__name__) + # Define the directory for generated images images_dir = "./generated_images" @@ -155,7 +157,7 @@ class Api: conversations[provider][conversation_id] = chunk yield self._format_json("conversation", conversation_id) elif isinstance(chunk, Exception): - logging.exception(chunk) + logger.exception(chunk) yield self._format_json("message", get_error_message(chunk)) elif isinstance(chunk, ImagePreview): yield self._format_json("preview", chunk.to_string()) @@ -165,7 +167,7 @@ class Api: elif not isinstance(chunk, FinishReason): yield self._format_json("content", str(chunk)) except Exception as e: - logging.exception(e) + logger.exception(e) yield self._format_json('error', get_error_message(e)) async def _copy_images(self, images: list[str], cookies: Optional[Cookies] = None): diff --git a/g4f/image.py b/g4f/image.py index 6561b83a..556ec43d 100644 --- a/g4f/image.py +++ b/g4f/image.py @@ -23,6 +23,11 @@ EXTENSIONS_MAP: dict[str, str] = { "image/webp": "webp", } +def fix_url(url:str) -> str: + """ replace ' ' by '+' (to be markdown compliant)""" + return url.replace(" ","+") + + def to_image(image: ImageType, is_svg: bool = False) -> Image: """ Converts the input image to a PIL Image object. @@ -212,12 +217,12 @@ def format_images_markdown(images: Union[str, list], alt: str, preview: Union[st str: The formatted markdown string. """ if isinstance(images, str): - result = f"[![{alt}]({preview.replace('{image}', images) if preview else images})]({images})" + result = f"[![{alt}]({fix_url(preview.replace('{image}', images) if preview else images)})]({fix_url(images)})" else: if not isinstance(preview, list): preview = [preview.replace('{image}', image) if preview else image for image in images] result = "\n".join( - f"[![#{idx+1} {alt}]({preview[idx]})]({image})" + f"[![#{idx+1} {alt}]({fix_url(preview[idx])})]({fix_url(image)})" #f'[<img src="{preview[idx]}" width="200" alt="#{idx+1} {alt}">]({image})' for idx, image in enumerate(images) ) @@ -302,4 +307,4 @@ class ImageRequest: self.options = options def get(self, key: str): - return self.options.get(key)
\ No newline at end of file + return self.options.get(key) diff --git a/g4f/providers/base_provider.py b/g4f/providers/base_provider.py index a03dcbba..5d48f2e0 100644 --- a/g4f/providers/base_provider.py +++ b/g4f/providers/base_provider.py @@ -248,7 +248,7 @@ class AsyncGeneratorProvider(AsyncProvider): str: The created result as a string. """ return "".join([ - chunk async for chunk in cls.create_async_generator(model, messages, stream=False, **kwargs) + str(chunk) async for chunk in cls.create_async_generator(model, messages, stream=False, **kwargs) if not isinstance(chunk, (Exception, FinishReason)) ]) diff --git a/requirements.txt b/requirements.txt index 1f75adf7..1a014bac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,6 @@ PyExecJS duckduckgo-search>=5.0 nest_asyncio werkzeug -loguru pillow platformdirs fastapi @@ -39,7 +39,7 @@ EXTRA_REQUIRE = { "pillow", # image "cairosvg", # svg image "werkzeug", "flask", # gui - "loguru", "fastapi", # api + "fastapi", # api "uvicorn", "nest_asyncio", # api "pycryptodome" # openai ], |