From be9b8f796cb01483cf6dd807dfc6a71c51433c16 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Tue, 3 Oct 2023 22:12:56 +0200 Subject: Add streaming in openai chat Fetch access token with chromedriver --- g4f/Provider/OpenaiChat.py | 73 +++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 23 deletions(-) (limited to 'g4f/Provider/OpenaiChat.py') diff --git a/g4f/Provider/OpenaiChat.py b/g4f/Provider/OpenaiChat.py index f7dc8298..fbd26d7c 100644 --- a/g4f/Provider/OpenaiChat.py +++ b/g4f/Provider/OpenaiChat.py @@ -1,14 +1,14 @@ from __future__ import annotations -from curl_cffi.requests import AsyncSession import uuid import json -from .base_provider import AsyncProvider, get_cookies, format_prompt +from .base_provider import AsyncGeneratorProvider +from .helper import get_browser, get_cookies, format_prompt from ..typing import AsyncGenerator +from ..requests import StreamSession - -class OpenaiChat(AsyncProvider): +class OpenaiChat(AsyncGeneratorProvider): url = "https://chat.openai.com" needs_auth = True working = True @@ -16,7 +16,7 @@ class OpenaiChat(AsyncProvider): _access_token = None @classmethod - async def create_async( + async def create_async_generator( cls, model: str, messages: list[dict[str, str]], @@ -32,7 +32,7 @@ class OpenaiChat(AsyncProvider): "Accept": "text/event-stream", "Authorization": f"Bearer {access_token}", } - async with AsyncSession(proxies=proxies, headers=headers, impersonate="chrome107") as session: + async with StreamSession(proxies=proxies, headers=headers, impersonate="chrome107") as session: messages = [ { "id": str(uuid.uuid4()), @@ -48,31 +48,58 @@ class OpenaiChat(AsyncProvider): "model": "text-davinci-002-render-sha", "history_and_training_disabled": True, } - response = await session.post("https://chat.openai.com/backend-api/conversation", json=data) - response.raise_for_status() - last_message = None - for line in response.content.decode().splitlines(): - if line.startswith("data: "): - line = line[6:] - if line == "[DONE]": - break - line = json.loads(line) - if "message" in line: - last_message = line["message"]["content"]["parts"][0] - return last_message + async with session.post(f"{cls.url}/backend-api/conversation", json=data) as response: + response.raise_for_status() + last_message = "" + async for line in response.iter_lines(): + if line.startswith(b"data: "): + line = line[6:] + if line == b"[DONE]": + break + line = json.loads(line) + if "message" in line and not line["message"]["end_turn"]: + new_message = line["message"]["content"]["parts"][0] + yield new_message[len(last_message):] + last_message = new_message + + @classmethod + def fetch_access_token(cls) -> str: + try: + from selenium.webdriver.common.by import By + from selenium.webdriver.support.ui import WebDriverWait + from selenium.webdriver.support import expected_conditions as EC + except ImportError: + return + driver = get_browser() + if not driver: + return + + driver.get(f"{cls.url}/") + try: + WebDriverWait(driver, 1200).until( + EC.presence_of_element_located((By.ID, "prompt-textarea")) + ) + javascript = "return (await (await fetch('/api/auth/session')).json())['accessToken']" + return driver.execute_script(javascript) + finally: + driver.quit() @classmethod async def get_access_token(cls, cookies: dict = None, proxies: dict = None) -> str: if not cls._access_token: cookies = cookies if cookies else get_cookies("chat.openai.com") - async with AsyncSession(proxies=proxies, cookies=cookies, impersonate="chrome107") as session: - response = await session.get("https://chat.openai.com/api/auth/session") - response.raise_for_status() - cls._access_token = response.json()["accessToken"] + async with StreamSession(proxies=proxies, cookies=cookies, impersonate="chrome107") as session: + async with session.get(f"{cls.url}/api/auth/session") as response: + response.raise_for_status() + auth = await response.json() + if "accessToken" in auth: + cls._access_token = auth["accessToken"] + cls._access_token = cls.fetch_access_token() + if not cls._access_token: + raise RuntimeError("Missing access token") return cls._access_token - @classmethod @property def params(cls): -- cgit v1.2.3 From 5b2efa4aaf00cb5b5b169c83f2690630495a962e Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Tue, 3 Oct 2023 23:53:17 +0200 Subject: Fix fetch_access_token in openai --- g4f/Provider/OpenaiChat.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'g4f/Provider/OpenaiChat.py') diff --git a/g4f/Provider/OpenaiChat.py b/g4f/Provider/OpenaiChat.py index fbd26d7c..ca148da2 100644 --- a/g4f/Provider/OpenaiChat.py +++ b/g4f/Provider/OpenaiChat.py @@ -63,7 +63,7 @@ class OpenaiChat(AsyncGeneratorProvider): last_message = new_message @classmethod - def fetch_access_token(cls) -> str: + def browse_access_token(cls) -> str: try: from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait @@ -85,19 +85,25 @@ class OpenaiChat(AsyncGeneratorProvider): finally: driver.quit() + @classmethod + async def fetch_access_token(cls, cookies: dict, proxies: dict = None) -> str: + async with StreamSession(proxies=proxies, cookies=cookies, impersonate="chrome107") as session: + async with session.get(f"{cls.url}/api/auth/session") as response: + response.raise_for_status() + auth = await response.json() + if "accessToken" in auth: + return auth["accessToken"] + @classmethod async def get_access_token(cls, cookies: dict = None, proxies: dict = None) -> str: if not cls._access_token: cookies = cookies if cookies else get_cookies("chat.openai.com") - async with StreamSession(proxies=proxies, cookies=cookies, impersonate="chrome107") as session: - async with session.get(f"{cls.url}/api/auth/session") as response: - response.raise_for_status() - auth = await response.json() - if "accessToken" in auth: - cls._access_token = auth["accessToken"] - cls._access_token = cls.fetch_access_token() - if not cls._access_token: - raise RuntimeError("Missing access token") + if cookies: + cls._access_token = await cls.fetch_access_token(cookies, proxies) + if not cls._access_token: + cls._access_token = cls.browse_access_token() + if not cls._access_token: + raise RuntimeError("Read access token failed") return cls._access_token @classmethod -- cgit v1.2.3 From 136770e05b63fd1482665eac5f90eba5bd10e4c5 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Wed, 4 Oct 2023 03:15:17 +0200 Subject: Use custom user dir --- g4f/Provider/OpenaiChat.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'g4f/Provider/OpenaiChat.py') diff --git a/g4f/Provider/OpenaiChat.py b/g4f/Provider/OpenaiChat.py index ca148da2..8f183fb9 100644 --- a/g4f/Provider/OpenaiChat.py +++ b/g4f/Provider/OpenaiChat.py @@ -1,7 +1,6 @@ from __future__ import annotations -import uuid -import json +import uuid, json, time from .base_provider import AsyncGeneratorProvider from .helper import get_browser, get_cookies, format_prompt @@ -56,8 +55,13 @@ class OpenaiChat(AsyncGeneratorProvider): line = line[6:] if line == b"[DONE]": break - line = json.loads(line) - if "message" in line and not line["message"]["end_turn"]: + try: + line = json.loads(line) + except: + continue + if "message" not in line or "message_type" not in line["message"]["metadata"]: + continue + if line["message"]["metadata"]["message_type"] == "next": new_message = line["message"]["content"]["parts"][0] yield new_message[len(last_message):] last_message = new_message @@ -68,11 +72,9 @@ class OpenaiChat(AsyncGeneratorProvider): from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC - except ImportError: - return - driver = get_browser() - if not driver: + driver = get_browser() + except ImportError: return driver.get(f"{cls.url}/") @@ -83,6 +85,7 @@ class OpenaiChat(AsyncGeneratorProvider): javascript = "return (await (await fetch('/api/auth/session')).json())['accessToken']" return driver.execute_script(javascript) finally: + time.sleep(1) driver.quit() @classmethod -- cgit v1.2.3 From 6a61cf811655fa87dbcb196025cc0b6040502293 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Wed, 4 Oct 2023 07:20:51 +0200 Subject: Sort providers in new dirs --- g4f/Provider/OpenaiChat.py | 124 --------------------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 g4f/Provider/OpenaiChat.py (limited to 'g4f/Provider/OpenaiChat.py') diff --git a/g4f/Provider/OpenaiChat.py b/g4f/Provider/OpenaiChat.py deleted file mode 100644 index 8f183fb9..00000000 --- a/g4f/Provider/OpenaiChat.py +++ /dev/null @@ -1,124 +0,0 @@ -from __future__ import annotations - -import uuid, json, time - -from .base_provider import AsyncGeneratorProvider -from .helper import get_browser, get_cookies, format_prompt -from ..typing import AsyncGenerator -from ..requests import StreamSession - -class OpenaiChat(AsyncGeneratorProvider): - url = "https://chat.openai.com" - needs_auth = True - working = True - supports_gpt_35_turbo = True - _access_token = None - - @classmethod - async def create_async_generator( - cls, - model: str, - messages: list[dict[str, str]], - proxy: str = None, - access_token: str = None, - cookies: dict = None, - **kwargs: dict - ) -> AsyncGenerator: - proxies = {"https": proxy} - if not access_token: - access_token = await cls.get_access_token(cookies, proxies) - headers = { - "Accept": "text/event-stream", - "Authorization": f"Bearer {access_token}", - } - async with StreamSession(proxies=proxies, headers=headers, impersonate="chrome107") as session: - messages = [ - { - "id": str(uuid.uuid4()), - "author": {"role": "user"}, - "content": {"content_type": "text", "parts": [format_prompt(messages)]}, - }, - ] - data = { - "action": "next", - "messages": messages, - "conversation_id": None, - "parent_message_id": str(uuid.uuid4()), - "model": "text-davinci-002-render-sha", - "history_and_training_disabled": True, - } - async with session.post(f"{cls.url}/backend-api/conversation", json=data) as response: - response.raise_for_status() - last_message = "" - async for line in response.iter_lines(): - if line.startswith(b"data: "): - line = line[6:] - if line == b"[DONE]": - break - try: - line = json.loads(line) - except: - continue - if "message" not in line or "message_type" not in line["message"]["metadata"]: - continue - if line["message"]["metadata"]["message_type"] == "next": - new_message = line["message"]["content"]["parts"][0] - yield new_message[len(last_message):] - last_message = new_message - - @classmethod - def browse_access_token(cls) -> str: - try: - from selenium.webdriver.common.by import By - from selenium.webdriver.support.ui import WebDriverWait - from selenium.webdriver.support import expected_conditions as EC - - driver = get_browser() - except ImportError: - return - - driver.get(f"{cls.url}/") - try: - WebDriverWait(driver, 1200).until( - EC.presence_of_element_located((By.ID, "prompt-textarea")) - ) - javascript = "return (await (await fetch('/api/auth/session')).json())['accessToken']" - return driver.execute_script(javascript) - finally: - time.sleep(1) - driver.quit() - - @classmethod - async def fetch_access_token(cls, cookies: dict, proxies: dict = None) -> str: - async with StreamSession(proxies=proxies, cookies=cookies, impersonate="chrome107") as session: - async with session.get(f"{cls.url}/api/auth/session") as response: - response.raise_for_status() - auth = await response.json() - if "accessToken" in auth: - return auth["accessToken"] - - @classmethod - async def get_access_token(cls, cookies: dict = None, proxies: dict = None) -> str: - if not cls._access_token: - cookies = cookies if cookies else get_cookies("chat.openai.com") - if cookies: - cls._access_token = await cls.fetch_access_token(cookies, proxies) - if not cls._access_token: - cls._access_token = cls.browse_access_token() - if not cls._access_token: - raise RuntimeError("Read access token failed") - return cls._access_token - - @classmethod - @property - def params(cls): - params = [ - ("model", "str"), - ("messages", "list[dict[str, str]]"), - ("stream", "bool"), - ("proxy", "str"), - ("access_token", "str"), - ("cookies", "dict[str, str]") - ] - param = ", ".join([": ".join(p) for p in params]) - return f"g4f.provider.{cls.__name__} supports: ({param})" \ No newline at end of file -- cgit v1.2.3