summaryrefslogtreecommitdiffstats
path: root/g4f/Provider
diff options
context:
space:
mode:
authorH Lohaus <hlohaus@users.noreply.github.com>2024-01-26 07:54:13 +0100
committerGitHub <noreply@github.com>2024-01-26 07:54:13 +0100
commitfeb83c168b0a57ecd8c511aa654209c5f40da30e (patch)
tree84ef9a576064b7480e339426d9966b17a3102cad /g4f/Provider
parentMerge pull request #1510 from hlohaus/sort (diff)
downloadgpt4free-feb83c168b0a57ecd8c511aa654209c5f40da30e.tar
gpt4free-feb83c168b0a57ecd8c511aa654209c5f40da30e.tar.gz
gpt4free-feb83c168b0a57ecd8c511aa654209c5f40da30e.tar.bz2
gpt4free-feb83c168b0a57ecd8c511aa654209c5f40da30e.tar.lz
gpt4free-feb83c168b0a57ecd8c511aa654209c5f40da30e.tar.xz
gpt4free-feb83c168b0a57ecd8c511aa654209c5f40da30e.tar.zst
gpt4free-feb83c168b0a57ecd8c511aa654209c5f40da30e.zip
Diffstat (limited to 'g4f/Provider')
-rw-r--r--g4f/Provider/Bing.py31
-rw-r--r--g4f/Provider/DeepInfra.py11
-rw-r--r--g4f/Provider/GptForLove.py11
-rw-r--r--g4f/Provider/HuggingChat.py2
-rw-r--r--g4f/Provider/PerplexityLabs.py8
-rw-r--r--g4f/Provider/Phind.py1
-rw-r--r--g4f/Provider/Vercel.py15
-rw-r--r--g4f/Provider/base_provider.py1
-rw-r--r--g4f/Provider/bing/conversation.py2
-rw-r--r--g4f/Provider/bing/create_images.py24
-rw-r--r--g4f/Provider/bing/upload_image.py51
-rw-r--r--g4f/Provider/deprecated/ChatgptDuo.py4
-rw-r--r--g4f/Provider/deprecated/GetGpt.py30
-rw-r--r--g4f/Provider/helper.py68
-rw-r--r--g4f/Provider/needs_auth/Bard.py12
-rw-r--r--g4f/Provider/needs_auth/OpenaiChat.py52
-rw-r--r--g4f/Provider/selenium/PerplexityAi.py12
17 files changed, 185 insertions, 150 deletions
diff --git a/g4f/Provider/Bing.py b/g4f/Provider/Bing.py
index 11bb1414..32879fa6 100644
--- a/g4f/Provider/Bing.py
+++ b/g4f/Provider/Bing.py
@@ -9,7 +9,7 @@ from urllib import parse
from aiohttp import ClientSession, ClientTimeout, BaseConnector
from ..typing import AsyncResult, Messages, ImageType
-from ..image import ImageResponse
+from ..image import ImageResponse, ImageRequest
from .base_provider import AsyncGeneratorProvider
from .helper import get_connector
from .bing.upload_image import upload_image
@@ -154,6 +154,11 @@ class Defaults:
'SRCHHPGUSR' : f'HV={int(time.time())}',
}
+class ConversationStyleOptionSets():
+ CREATIVE = ["h3imaginative", "clgalileo", "gencontentv3"]
+ BALANCED = ["galileo"]
+ PRECISE = ["h3precise", "clgalileo"]
+
def format_message(msg: dict) -> str:
"""
Formats a message dictionary into a JSON string with a delimiter.
@@ -168,7 +173,7 @@ def create_message(
prompt: str,
tone: str,
context: str = None,
- image_response: ImageResponse = None,
+ image_request: ImageRequest = None,
web_search: bool = False,
gpt4_turbo: bool = False
) -> str:
@@ -179,7 +184,7 @@ def create_message(
:param prompt: The user's input prompt.
:param tone: The desired tone for the response.
:param context: Additional context for the prompt.
- :param image_response: The response if an image is involved.
+ :param image_request: The image request with the url.
:param web_search: Flag to enable web search.
:param gpt4_turbo: Flag to enable GPT-4 Turbo.
:return: A formatted string message for the Bing API.
@@ -187,11 +192,11 @@ def create_message(
options_sets = Defaults.optionsSets
# Append tone-specific options
if tone == Tones.creative:
- options_sets.append("h3imaginative")
+ options_sets.extend(ConversationStyleOptionSets.CREATIVE)
elif tone == Tones.precise:
- options_sets.append("h3precise")
+ options_sets.extend(ConversationStyleOptionSets.PRECISE)
elif tone == Tones.balanced:
- options_sets.append("galileo")
+ options_sets.extend(ConversationStyleOptionSets.BALANCED)
else:
options_sets.append("harmonyv3")
@@ -233,9 +238,9 @@ def create_message(
'type': 4
}
- if image_response and image_response.get('imageUrl') and image_response.get('originalImageUrl'):
- struct['arguments'][0]['message']['originalImageUrl'] = image_response.get('originalImageUrl')
- struct['arguments'][0]['message']['imageUrl'] = image_response.get('imageUrl')
+ if image_request and image_request.get('imageUrl') and image_request.get('originalImageUrl'):
+ struct['arguments'][0]['message']['originalImageUrl'] = image_request.get('originalImageUrl')
+ struct['arguments'][0]['message']['imageUrl'] = image_request.get('imageUrl')
struct['arguments'][0]['experienceType'] = None
struct['arguments'][0]['attachedFileInfo'] = {"fileName": None, "fileType": None}
@@ -282,9 +287,9 @@ async def stream_generate(
timeout=ClientTimeout(total=timeout), headers=headers, connector=connector
) as session:
conversation = await create_conversation(session)
- image_response = await upload_image(session, image, tone) if image else None
- if image_response:
- yield image_response
+ image_request = await upload_image(session, image, tone) if image else None
+ if image_request:
+ yield image_request
try:
async with session.ws_connect(
@@ -294,7 +299,7 @@ async def stream_generate(
) as wss:
await wss.send_str(format_message({'protocol': 'json', 'version': 1}))
await wss.receive(timeout=timeout)
- await wss.send_str(create_message(conversation, prompt, tone, context, image_response, web_search, gpt4_turbo))
+ await wss.send_str(create_message(conversation, prompt, tone, context, image_request, web_search, gpt4_turbo))
response_txt = ''
returned_text = ''
diff --git a/g4f/Provider/DeepInfra.py b/g4f/Provider/DeepInfra.py
index 2f34b679..09b9464e 100644
--- a/g4f/Provider/DeepInfra.py
+++ b/g4f/Provider/DeepInfra.py
@@ -13,11 +13,12 @@ class DeepInfra(AsyncGeneratorProvider, ProviderModelMixin):
supports_message_history = True
default_model = 'meta-llama/Llama-2-70b-chat-hf'
- @staticmethod
- def get_models():
- url = 'https://api.deepinfra.com/models/featured'
- models = requests.get(url).json()
- return [model['model_name'] for model in models]
+ @classmethod
+ def get_models(cls):
+ if not cls.models:
+ url = 'https://api.deepinfra.com/models/featured'
+ cls.models = requests.get(url).json()
+ return cls.models
@classmethod
async def create_async_generator(
diff --git a/g4f/Provider/GptForLove.py b/g4f/Provider/GptForLove.py
index 07e3406f..cc82da21 100644
--- a/g4f/Provider/GptForLove.py
+++ b/g4f/Provider/GptForLove.py
@@ -1,11 +1,18 @@
from __future__ import annotations
from aiohttp import ClientSession
-import execjs, os, json
+import os
+import json
+try:
+ import execjs
+ has_requirements = True
+except ImportError:
+ has_requirements = False
from ..typing import AsyncResult, Messages
from .base_provider import AsyncGeneratorProvider
from .helper import format_prompt
+from ..errors import MissingRequirementsError
class GptForLove(AsyncGeneratorProvider):
url = "https://ai18.gptforlove.com"
@@ -20,6 +27,8 @@ class GptForLove(AsyncGeneratorProvider):
proxy: str = None,
**kwargs
) -> AsyncResult:
+ if not has_requirements:
+ raise MissingRequirementsError('Install "PyExecJS" package')
if not model:
model = "gpt-3.5-turbo"
headers = {
diff --git a/g4f/Provider/HuggingChat.py b/g4f/Provider/HuggingChat.py
index 79e4ae38..9aa93878 100644
--- a/g4f/Provider/HuggingChat.py
+++ b/g4f/Provider/HuggingChat.py
@@ -39,7 +39,7 @@ class HuggingChat(AsyncGeneratorProvider, ProviderModelMixin):
**kwargs
) -> AsyncResult:
if not cookies:
- cookies = get_cookies(".huggingface.co")
+ cookies = get_cookies(".huggingface.co", False)
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
diff --git a/g4f/Provider/PerplexityLabs.py b/g4f/Provider/PerplexityLabs.py
index 5002b39f..a7b98f7c 100644
--- a/g4f/Provider/PerplexityLabs.py
+++ b/g4f/Provider/PerplexityLabs.py
@@ -14,12 +14,12 @@ WS_URL = "wss://labs-api.perplexity.ai/socket.io/"
class PerplexityLabs(AsyncGeneratorProvider, ProviderModelMixin):
url = "https://labs.perplexity.ai"
working = True
+ default_model = 'pplx-70b-online'
models = [
'pplx-7b-online', 'pplx-70b-online', 'pplx-7b-chat', 'pplx-70b-chat', 'mistral-7b-instruct',
'codellama-34b-instruct', 'llama-2-70b-chat', 'llava-7b-chat', 'mixtral-8x7b-instruct',
'mistral-medium', 'related'
]
- default_model = 'pplx-70b-online'
model_aliases = {
"mistralai/Mistral-7B-Instruct-v0.1": "mistral-7b-instruct",
"meta-llama/Llama-2-70b-chat-hf": "llama-2-70b-chat",
@@ -52,8 +52,7 @@ class PerplexityLabs(AsyncGeneratorProvider, ProviderModelMixin):
async with ClientSession(headers=headers, connector=get_connector(connector, proxy)) as session:
t = format(random.getrandbits(32), '08x')
async with session.get(
- f"{API_URL}?EIO=4&transport=polling&t={t}",
- proxy=proxy
+ f"{API_URL}?EIO=4&transport=polling&t={t}"
) as response:
text = await response.text()
@@ -61,8 +60,7 @@ class PerplexityLabs(AsyncGeneratorProvider, ProviderModelMixin):
post_data = '40{"jwt":"anonymous-ask-user"}'
async with session.post(
f'{API_URL}?EIO=4&transport=polling&t={t}&sid={sid}',
- data=post_data,
- proxy=proxy
+ data=post_data
) as response:
assert await response.text() == 'OK'
diff --git a/g4f/Provider/Phind.py b/g4f/Provider/Phind.py
index dfc8f992..dbf1e7ae 100644
--- a/g4f/Provider/Phind.py
+++ b/g4f/Provider/Phind.py
@@ -9,7 +9,6 @@ from ..requests import StreamSession
class Phind(AsyncGeneratorProvider):
url = "https://www.phind.com"
working = True
- supports_gpt_4 = True
supports_stream = True
supports_message_history = True
diff --git a/g4f/Provider/Vercel.py b/g4f/Provider/Vercel.py
index 466ea3de..8d2137bf 100644
--- a/g4f/Provider/Vercel.py
+++ b/g4f/Provider/Vercel.py
@@ -1,10 +1,16 @@
from __future__ import annotations
-import json, base64, requests, execjs, random, uuid
+import json, base64, requests, random, uuid
+
+try:
+ import execjs
+ has_requirements = True
+except ImportError:
+ has_requirements = False
from ..typing import Messages, TypedDict, CreateResult, Any
from .base_provider import AbstractProvider
-from ..debug import logging
+from ..errors import MissingRequirementsError
class Vercel(AbstractProvider):
url = 'https://sdk.vercel.ai'
@@ -21,10 +27,11 @@ class Vercel(AbstractProvider):
proxy: str = None,
**kwargs
) -> CreateResult:
-
+ if not has_requirements:
+ raise MissingRequirementsError('Install "PyExecJS" package')
+
if not model:
model = "gpt-3.5-turbo"
-
elif model not in model_info:
raise ValueError(f"Vercel does not support {model}")
diff --git a/g4f/Provider/base_provider.py b/g4f/Provider/base_provider.py
index e1dcd24d..b173db4e 100644
--- a/g4f/Provider/base_provider.py
+++ b/g4f/Provider/base_provider.py
@@ -1,4 +1,5 @@
from __future__ import annotations
+
import sys
import asyncio
from asyncio import AbstractEventLoop
diff --git a/g4f/Provider/bing/conversation.py b/g4f/Provider/bing/conversation.py
index 36ada3b0..388bdd6b 100644
--- a/g4f/Provider/bing/conversation.py
+++ b/g4f/Provider/bing/conversation.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from aiohttp import ClientSession
class Conversation:
diff --git a/g4f/Provider/bing/create_images.py b/g4f/Provider/bing/create_images.py
index af39ef1e..4fa85929 100644
--- a/g4f/Provider/bing/create_images.py
+++ b/g4f/Provider/bing/create_images.py
@@ -2,21 +2,28 @@
This module provides functionalities for creating and managing images using Bing's service.
It includes functions for user login, session creation, image creation, and processing.
"""
+from __future__ import annotations
import asyncio
import time
import json
import os
from aiohttp import ClientSession, BaseConnector
-from bs4 import BeautifulSoup
from urllib.parse import quote
from typing import Generator, List, Dict
+try:
+ from bs4 import BeautifulSoup
+ has_requirements = True
+except ImportError:
+ has_requirements = False
+
from ..create_images import CreateImagesProvider
from ..helper import get_cookies, get_connector
from ...webdriver import WebDriver, get_driver_cookies, get_browser
from ...base_provider import ProviderType
from ...image import ImageResponse
+from ...errors import MissingRequirementsError, MissingAccessToken
BING_URL = "https://www.bing.com"
TIMEOUT_LOGIN = 1200
@@ -97,6 +104,8 @@ async def create_images(session: ClientSession, prompt: str, proxy: str = None,
Raises:
RuntimeError: If image creation fails or times out.
"""
+ if not has_requirements:
+ raise MissingRequirementsError('Install "beautifulsoup4" package')
url_encoded_prompt = quote(prompt)
payload = f"q={url_encoded_prompt}&rt=4&FORM=GENCRE"
url = f"{BING_URL}/images/create?q={url_encoded_prompt}&rt=4&FORM=GENCRE"
@@ -193,7 +202,11 @@ class CreateImagesBing:
Yields:
Generator[str, None, None]: The final output as markdown formatted string with images.
"""
- cookies = self.cookies or get_cookies(".bing.com")
+ try:
+ cookies = self.cookies or get_cookies(".bing.com")
+ except MissingRequirementsError as e:
+ raise MissingAccessToken(f'Missing "_U" cookie. {e}')
+
if "_U" not in cookies:
login_url = os.environ.get("G4F_LOGIN_URL")
if login_url:
@@ -211,9 +224,12 @@ class CreateImagesBing:
Returns:
str: Markdown formatted string with images.
"""
- cookies = self.cookies or get_cookies(".bing.com")
+ try:
+ cookies = self.cookies or get_cookies(".bing.com")
+ except MissingRequirementsError as e:
+ raise MissingAccessToken(f'Missing "_U" cookie. {e}')
if "_U" not in cookies:
- raise RuntimeError('"_U" cookie is missing')
+ raise MissingAccessToken('Missing "_U" cookie')
proxy = os.environ.get("G4F_PROXY")
async with create_session(cookies, proxy) as session:
images = await create_images(session, prompt, self.proxy)
diff --git a/g4f/Provider/bing/upload_image.py b/g4f/Provider/bing/upload_image.py
index bb5687a8..f9e11561 100644
--- a/g4f/Provider/bing/upload_image.py
+++ b/g4f/Provider/bing/upload_image.py
@@ -1,17 +1,14 @@
"""
Module to handle image uploading and processing for Bing AI integrations.
"""
-
from __future__ import annotations
-import string
-import random
+
import json
import math
-from aiohttp import ClientSession
-from PIL import Image
+from aiohttp import ClientSession, FormData
from ...typing import ImageType, Tuple
-from ...image import to_image, process_image, to_base64, ImageResponse
+from ...image import to_image, process_image, to_base64_jpg, ImageRequest, Image
IMAGE_CONFIG = {
"maxImagePixels": 360000,
@@ -24,7 +21,7 @@ async def upload_image(
image_data: ImageType,
tone: str,
proxy: str = None
-) -> ImageResponse:
+) -> ImageRequest:
"""
Uploads an image to Bing's AI service and returns the image response.
@@ -38,22 +35,22 @@ async def upload_image(
RuntimeError: If the image upload fails.
Returns:
- ImageResponse: The response from the image upload.
+ ImageRequest: The response from the image upload.
"""
image = to_image(image_data)
new_width, new_height = calculate_new_dimensions(image)
- processed_img = process_image(image, new_width, new_height)
- img_binary_data = to_base64(processed_img, IMAGE_CONFIG['imageCompressionRate'])
+ image = process_image(image, new_width, new_height)
+ img_binary_data = to_base64_jpg(image, IMAGE_CONFIG['imageCompressionRate'])
- data, boundary = build_image_upload_payload(img_binary_data, tone)
- headers = prepare_headers(session, boundary)
+ data = build_image_upload_payload(img_binary_data, tone)
+ headers = prepare_headers(session)
async with session.post("https://www.bing.com/images/kblob", data=data, headers=headers, proxy=proxy) as response:
if response.status != 200:
raise RuntimeError("Failed to upload image.")
return parse_image_response(await response.json())
-def calculate_new_dimensions(image: Image.Image) -> Tuple[int, int]:
+def calculate_new_dimensions(image: Image) -> Tuple[int, int]:
"""
Calculates the new dimensions for the image based on the maximum allowed pixels.
@@ -70,7 +67,7 @@ def calculate_new_dimensions(image: Image.Image) -> Tuple[int, int]:
return int(width * scale_factor), int(height * scale_factor)
return width, height
-def build_image_upload_payload(image_bin: str, tone: str) -> Tuple[str, str]:
+def build_image_upload_payload(image_bin: str, tone: str) -> FormData:
"""
Builds the payload for image uploading.
@@ -81,18 +78,11 @@ def build_image_upload_payload(image_bin: str, tone: str) -> Tuple[str, str]:
Returns:
Tuple[str, str]: The data and boundary for the payload.
"""
- boundary = "----WebKitFormBoundary" + ''.join(random.choices(string.ascii_letters + string.digits, k=16))
- data = f"""--{boundary}
-Content-Disposition: form-data; name="knowledgeRequest"
-
-{json.dumps(build_knowledge_request(tone), ensure_ascii=False)}
---{boundary}
-Content-Disposition: form-data; name="imageBase64"
-
-{image_bin}
---{boundary}--
-"""
- return data, boundary
+ data = FormData()
+ knowledge_request = json.dumps(build_knowledge_request(tone), ensure_ascii=False)
+ data.add_field('knowledgeRequest', knowledge_request, content_type="application/json")
+ data.add_field('imageBase64', image_bin)
+ return data
def build_knowledge_request(tone: str) -> dict:
"""
@@ -119,7 +109,7 @@ def build_knowledge_request(tone: str) -> dict:
}
}
-def prepare_headers(session: ClientSession, boundary: str) -> dict:
+def prepare_headers(session: ClientSession) -> dict:
"""
Prepares the headers for the image upload request.
@@ -131,12 +121,11 @@ def prepare_headers(session: ClientSession, boundary: str) -> dict:
dict: The headers for the request.
"""
headers = session.headers.copy()
- headers["Content-Type"] = f'multipart/form-data; boundary={boundary}'
headers["Referer"] = 'https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx'
headers["Origin"] = 'https://www.bing.com'
return headers
-def parse_image_response(response: dict) -> ImageResponse:
+def parse_image_response(response: dict) -> ImageRequest:
"""
Parses the response from the image upload.
@@ -147,7 +136,7 @@ def parse_image_response(response: dict) -> ImageResponse:
RuntimeError: If parsing the image info fails.
Returns:
- ImageResponse: The parsed image response.
+ ImageRequest: The parsed image response.
"""
if not response.get('blobId'):
raise RuntimeError("Failed to parse image info.")
@@ -160,4 +149,4 @@ def parse_image_response(response: dict) -> ImageResponse:
if IMAGE_CONFIG["enableFaceBlurDebug"] else
f"https://www.bing.com/images/blob?bcid={result['bcid']}"
)
- return ImageResponse(result["imageUrl"], "", result) \ No newline at end of file
+ return ImageRequest(result["imageUrl"], "", result) \ No newline at end of file
diff --git a/g4f/Provider/deprecated/ChatgptDuo.py b/g4f/Provider/deprecated/ChatgptDuo.py
index c2d2de7a..bd9e195d 100644
--- a/g4f/Provider/deprecated/ChatgptDuo.py
+++ b/g4f/Provider/deprecated/ChatgptDuo.py
@@ -1,7 +1,7 @@
from __future__ import annotations
from ...typing import Messages
-from curl_cffi.requests import AsyncSession
+from ...requests import StreamSession
from ..base_provider import AsyncProvider, format_prompt
@@ -19,7 +19,7 @@ class ChatgptDuo(AsyncProvider):
timeout: int = 120,
**kwargs
) -> str:
- async with AsyncSession(
+ async with StreamSession(
impersonate="chrome107",
proxies={"https": proxy},
timeout=timeout
diff --git a/g4f/Provider/deprecated/GetGpt.py b/g4f/Provider/deprecated/GetGpt.py
index 69851ee5..dd586569 100644
--- a/g4f/Provider/deprecated/GetGpt.py
+++ b/g4f/Provider/deprecated/GetGpt.py
@@ -5,10 +5,10 @@ import os
import uuid
import requests
-try:
- from Crypto.Cipher import AES
-except ImportError:
- from Cryptodome.Cipher import AES
+# try:
+# from Crypto.Cipher import AES
+# except ImportError:
+# from Cryptodome.Cipher import AES
from ...typing import Any, CreateResult
from ..base_provider import AbstractProvider
@@ -57,19 +57,21 @@ class GetGpt(AbstractProvider):
def _encrypt(e: str):
- t = os.urandom(8).hex().encode('utf-8')
- n = os.urandom(8).hex().encode('utf-8')
- r = e.encode('utf-8')
+ # t = os.urandom(8).hex().encode('utf-8')
+ # n = os.urandom(8).hex().encode('utf-8')
+ # r = e.encode('utf-8')
- cipher = AES.new(t, AES.MODE_CBC, n)
- ciphertext = cipher.encrypt(_pad_data(r))
+ # cipher = AES.new(t, AES.MODE_CBC, n)
+ # ciphertext = cipher.encrypt(_pad_data(r))
- return ciphertext.hex() + t.decode('utf-8') + n.decode('utf-8')
+ # return ciphertext.hex() + t.decode('utf-8') + n.decode('utf-8')
+ return
def _pad_data(data: bytes) -> bytes:
- block_size = AES.block_size
- padding_size = block_size - len(data) % block_size
- padding = bytes([padding_size] * padding_size)
+ # block_size = AES.block_size
+ # padding_size = block_size - len(data) % block_size
+ # padding = bytes([padding_size] * padding_size)
- return data + padding
+ # return data + padding
+ return \ No newline at end of file
diff --git a/g4f/Provider/helper.py b/g4f/Provider/helper.py
index cf204e39..0af61d8d 100644
--- a/g4f/Provider/helper.py
+++ b/g4f/Provider/helper.py
@@ -1,57 +1,37 @@
from __future__ import annotations
-import asyncio
import os
import random
import secrets
import string
-from asyncio import AbstractEventLoop, BaseEventLoop
from aiohttp import BaseConnector
-from platformdirs import user_config_dir
-from browser_cookie3 import (
- chrome, chromium, opera, opera_gx,
- brave, edge, vivaldi, firefox,
- _LinuxPasswordManager, BrowserCookieError
-)
+
+try:
+ from platformdirs import user_config_dir
+ has_platformdirs = True
+except ImportError:
+ has_platformdirs = False
+try:
+ from browser_cookie3 import (
+ chrome, chromium, opera, opera_gx,
+ brave, edge, vivaldi, firefox,
+ _LinuxPasswordManager, BrowserCookieError
+ )
+ has_browser_cookie3 = True
+except ImportError:
+ has_browser_cookie3 = False
+
from ..typing import Dict, Messages, Optional
-from ..errors import AiohttpSocksError
+from ..errors import AiohttpSocksError, MissingRequirementsError
from .. import debug
# Global variable to store cookies
_cookies: Dict[str, Dict[str, str]] = {}
-def get_event_loop() -> AbstractEventLoop:
- """
- Get the current asyncio event loop. If the loop is closed or not set, create a new event loop.
- If a loop is running, handle nested event loops. Patch the loop if 'nest_asyncio' is installed.
-
- Returns:
- AbstractEventLoop: The current or new event loop.
- """
- try:
- loop = asyncio.get_event_loop()
- if isinstance(loop, BaseEventLoop):
- loop._check_closed()
- except RuntimeError:
- loop = asyncio.new_event_loop()
- asyncio.set_event_loop(loop)
- try:
- asyncio.get_running_loop()
- if not hasattr(loop.__class__, "_nest_patched"):
- import nest_asyncio
- nest_asyncio.apply(loop)
- except RuntimeError:
- pass
- except ImportError:
- raise RuntimeError(
- 'Use "create_async" instead of "create" function in a running event loop. Or install "nest_asyncio" package.'
- )
- return loop
-
-if os.environ.get('DBUS_SESSION_BUS_ADDRESS') == "/dev/null":
+if has_browser_cookie3 and os.environ.get('DBUS_SESSION_BUS_ADDRESS') == "/dev/null":
_LinuxPasswordManager.get_password = lambda a, b: b"secret"
-def get_cookies(domain_name: str = '') -> Dict[str, str]:
+def get_cookies(domain_name: str = '', raise_requirements_error: bool = True) -> Dict[str, str]:
"""
Load cookies for a given domain from all supported browsers and cache the results.
@@ -64,11 +44,11 @@ def get_cookies(domain_name: str = '') -> Dict[str, str]:
if domain_name in _cookies:
return _cookies[domain_name]
- cookies = _load_cookies_from_browsers(domain_name)
+ cookies = load_cookies_from_browsers(domain_name, raise_requirements_error)
_cookies[domain_name] = cookies
return cookies
-def _load_cookies_from_browsers(domain_name: str) -> Dict[str, str]:
+def load_cookies_from_browsers(domain_name: str, raise_requirements_error: bool = True) -> Dict[str, str]:
"""
Helper function to load cookies from various browsers.
@@ -78,6 +58,10 @@ def _load_cookies_from_browsers(domain_name: str) -> Dict[str, str]:
Returns:
Dict[str, str]: A dictionary of cookie names and values.
"""
+ if not has_browser_cookie3:
+ if raise_requirements_error:
+ raise MissingRequirementsError('Install "browser_cookie3" package')
+ return {}
cookies = {}
for cookie_fn in [_g4f, chrome, chromium, opera, opera_gx, brave, edge, vivaldi, firefox]:
try:
@@ -104,6 +88,8 @@ def _g4f(domain_name: str) -> list:
Returns:
list: List of cookies.
"""
+ if not has_platformdirs:
+ return []
user_data_dir = user_config_dir("g4f")
cookie_file = os.path.join(user_data_dir, "Default", "Cookies")
return [] if not os.path.exists(cookie_file) else chrome(cookie_file, domain_name)
diff --git a/g4f/Provider/needs_auth/Bard.py b/g4f/Provider/needs_auth/Bard.py
index aea67874..09ed1c3c 100644
--- a/g4f/Provider/needs_auth/Bard.py
+++ b/g4f/Provider/needs_auth/Bard.py
@@ -2,10 +2,14 @@ from __future__ import annotations
import time
import os
-from selenium.webdriver.common.by import By
-from selenium.webdriver.support.ui import WebDriverWait
-from selenium.webdriver.support import expected_conditions as EC
-from selenium.webdriver.common.keys import Keys
+
+try:
+ from selenium.webdriver.common.by import By
+ from selenium.webdriver.support.ui import WebDriverWait
+ from selenium.webdriver.support import expected_conditions as EC
+ from selenium.webdriver.common.keys import Keys
+except ImportError:
+ pass
from ...typing import CreateResult, Messages
from ..base_provider import AbstractProvider
diff --git a/g4f/Provider/needs_auth/OpenaiChat.py b/g4f/Provider/needs_auth/OpenaiChat.py
index 85866272..b07bd49b 100644
--- a/g4f/Provider/needs_auth/OpenaiChat.py
+++ b/g4f/Provider/needs_auth/OpenaiChat.py
@@ -1,21 +1,32 @@
from __future__ import annotations
+
import asyncio
import uuid
import json
import os
-from py_arkose_generator.arkose import get_values_for_request
-from async_property import async_cached_property
-from selenium.webdriver.common.by import By
-from selenium.webdriver.support.ui import WebDriverWait
-from selenium.webdriver.support import expected_conditions as EC
+try:
+ from py_arkose_generator.arkose import get_values_for_request
+ from async_property import async_cached_property
+ has_requirements = True
+except ImportError:
+ async_cached_property = property
+ has_requirements = False
+try:
+ from selenium.webdriver.common.by import By
+ from selenium.webdriver.support.ui import WebDriverWait
+ from selenium.webdriver.support import expected_conditions as EC
+ has_webdriver = True
+except ImportError:
+ has_webdriver = False
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
from ..helper import format_prompt, get_cookies
from ...webdriver import get_browser, get_driver_cookies
-from ...typing import AsyncResult, Messages
+from ...typing import AsyncResult, Messages, Cookies, ImageType
from ...requests import StreamSession
-from ...image import to_image, to_bytes, ImageType, ImageResponse
+from ...image import to_image, to_bytes, ImageResponse, ImageRequest
+from ...errors import MissingRequirementsError, MissingAccessToken
class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
@@ -27,12 +38,8 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
supports_gpt_35_turbo = True
supports_gpt_4 = True
default_model = None
- models = ["text-davinci-002-render-sha", "gpt-4", "gpt-4-gizmo"]
- model_aliases = {
- "gpt-3.5-turbo": "text-davinci-002-render-sha",
- }
+ models = ["gpt-3.5-turbo", "gpt-4", "gpt-4-gizmo"]
_cookies: dict = {}
- _default_model: str = None
@classmethod
async def create(
@@ -94,7 +101,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
session: StreamSession,
headers: dict,
image: ImageType
- ) -> ImageResponse:
+ ) -> ImageRequest:
"""
Upload an image to the service and get the download URL
@@ -104,7 +111,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
image: The image to upload, either a PIL Image object or a bytes object
Returns:
- An ImageResponse object that contains the download URL, file name, and other data
+ An ImageRequest object that contains the download URL, file name, and other data
"""
# Convert the image to a PIL Image object and get the extension
image = to_image(image)
@@ -145,7 +152,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
) as response:
response.raise_for_status()
download_url = (await response.json())["download_url"]
- return ImageResponse(download_url, image_data["file_name"], image_data)
+ return ImageRequest(download_url, image_data["file_name"], image_data)
@classmethod
async def get_default_model(cls, session: StreamSession, headers: dict):
@@ -169,7 +176,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
return cls.default_model
@classmethod
- def create_messages(cls, prompt: str, image_response: ImageResponse = None):
+ def create_messages(cls, prompt: str, image_response: ImageRequest = None):
"""
Create a list of messages for the user input
@@ -282,7 +289,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
proxy: str = None,
timeout: int = 120,
access_token: str = None,
- cookies: dict = None,
+ cookies: Cookies = None,
auto_continue: bool = False,
history_disabled: bool = True,
action: str = "next",
@@ -317,12 +324,16 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
Raises:
RuntimeError: If an error occurs during processing.
"""
+ if not has_requirements:
+ raise MissingRequirementsError('Install "py-arkose-generator" and "async_property" package')
if not parent_id:
parent_id = str(uuid.uuid4())
if not cookies:
- cookies = cls._cookies or get_cookies("chat.openai.com")
+ cookies = cls._cookies or get_cookies("chat.openai.com", False)
if not access_token and "access_token" in cookies:
access_token = cookies["access_token"]
+ if not access_token and not has_webdriver:
+ raise MissingAccessToken(f'Missing "access_token"')
if not access_token:
login_url = os.environ.get("G4F_LOGIN_URL")
if login_url:
@@ -331,7 +342,6 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
cls._cookies = cookies
headers = {"Authorization": f"Bearer {access_token}"}
-
async with StreamSession(
proxies={"https": proxy},
impersonate="chrome110",
@@ -346,13 +356,15 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
except Exception as e:
yield e
end_turn = EndTurn()
+ model = cls.get_model(model or await cls.get_default_model(session, headers))
+ model = "text-davinci-002-render-sha" if model == "gpt-3.5-turbo" else model
while not end_turn.is_end:
data = {
"action": action,
"arkose_token": await cls.get_arkose_token(session),
"conversation_id": conversation_id,
"parent_message_id": parent_id,
- "model": cls.get_model(model or await cls.get_default_model(session, headers)),
+ "model": model,
"history_and_training_disabled": history_disabled and not auto_continue,
}
if action != "continue":
diff --git a/g4f/Provider/selenium/PerplexityAi.py b/g4f/Provider/selenium/PerplexityAi.py
index 4796f709..8ae6ad2b 100644
--- a/g4f/Provider/selenium/PerplexityAi.py
+++ b/g4f/Provider/selenium/PerplexityAi.py
@@ -1,10 +1,14 @@
from __future__ import annotations
import time
-from selenium.webdriver.common.by import By
-from selenium.webdriver.support.ui import WebDriverWait
-from selenium.webdriver.support import expected_conditions as EC
-from selenium.webdriver.common.keys import Keys
+
+try:
+ from selenium.webdriver.common.by import By
+ from selenium.webdriver.support.ui import WebDriverWait
+ from selenium.webdriver.support import expected_conditions as EC
+ from selenium.webdriver.common.keys import Keys
+except ImportError:
+ pass
from ...typing import CreateResult, Messages
from ..base_provider import AbstractProvider