From 38dbe4b8e5ca7f9bc0508e1ba1bf878fd6d8c19c Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Mon, 22 Jan 2024 03:38:11 +0100 Subject: Improve CreateImagesBing Sort providers by category --- g4f/Provider/AItianhuSpace.py | 117 --------------------------------- g4f/Provider/Aichat.py | 66 ------------------- g4f/Provider/Berlin.py | 78 ---------------------- g4f/Provider/HuggingChat.py | 71 ++++++++++++++++++++ g4f/Provider/MyShell.py | 76 --------------------- g4f/Provider/Opchatgpts.py | 59 ----------------- g4f/Provider/PerplexityAi.py | 106 ----------------------------- g4f/Provider/TalkAi.py | 87 ------------------------ g4f/Provider/Yqcloud.py | 61 ----------------- g4f/Provider/__init__.py | 9 +-- g4f/Provider/bing/create_images.py | 63 +++++++----------- g4f/Provider/deprecated/Aichat.py | 64 ++++++++++++++++++ g4f/Provider/deprecated/Berlin.py | 78 ++++++++++++++++++++++ g4f/Provider/deprecated/Opchatgpts.py | 59 +++++++++++++++++ g4f/Provider/deprecated/Yqcloud.py | 61 +++++++++++++++++ g4f/Provider/deprecated/__init__.py | 6 +- g4f/Provider/needs_auth/HuggingChat.py | 71 -------------------- g4f/Provider/needs_auth/__init__.py | 1 - g4f/Provider/selenium/AItianhuSpace.py | 117 +++++++++++++++++++++++++++++++++ g4f/Provider/selenium/MyShell.py | 76 +++++++++++++++++++++ g4f/Provider/selenium/PerplexityAi.py | 106 +++++++++++++++++++++++++++++ g4f/Provider/selenium/TalkAi.py | 87 ++++++++++++++++++++++++ g4f/Provider/selenium/__init__.py | 6 +- 23 files changed, 755 insertions(+), 770 deletions(-) delete mode 100644 g4f/Provider/AItianhuSpace.py delete mode 100644 g4f/Provider/Aichat.py delete mode 100644 g4f/Provider/Berlin.py create mode 100644 g4f/Provider/HuggingChat.py delete mode 100644 g4f/Provider/MyShell.py delete mode 100644 g4f/Provider/Opchatgpts.py delete mode 100644 g4f/Provider/PerplexityAi.py delete mode 100644 g4f/Provider/TalkAi.py delete mode 100644 g4f/Provider/Yqcloud.py create mode 100644 g4f/Provider/deprecated/Aichat.py create mode 100644 g4f/Provider/deprecated/Berlin.py create mode 100644 g4f/Provider/deprecated/Opchatgpts.py create mode 100644 g4f/Provider/deprecated/Yqcloud.py delete mode 100644 g4f/Provider/needs_auth/HuggingChat.py create mode 100644 g4f/Provider/selenium/AItianhuSpace.py create mode 100644 g4f/Provider/selenium/MyShell.py create mode 100644 g4f/Provider/selenium/PerplexityAi.py create mode 100644 g4f/Provider/selenium/TalkAi.py (limited to 'g4f') diff --git a/g4f/Provider/AItianhuSpace.py b/g4f/Provider/AItianhuSpace.py deleted file mode 100644 index 11725db7..00000000 --- a/g4f/Provider/AItianhuSpace.py +++ /dev/null @@ -1,117 +0,0 @@ -from __future__ import annotations - -import time -import random - -from ..typing import CreateResult, Messages -from .base_provider import AbstractProvider -from .helper import format_prompt, get_random_string -from ..webdriver import WebDriver, WebDriverSession -from .. import debug - -class AItianhuSpace(AbstractProvider): - url = "https://chat3.aiyunos.top/" - working = True - supports_stream = True - supports_gpt_35_turbo = True - _domains = ["aitianhu.com", "aitianhu1.top"] - - @classmethod - def create_completion( - cls, - model: str, - messages: Messages, - stream: bool, - domain: str = None, - proxy: str = None, - timeout: int = 120, - webdriver: WebDriver = None, - headless: bool = True, - **kwargs - ) -> CreateResult: - if not model: - model = "gpt-3.5-turbo" - if not domain: - rand = get_random_string(6) - domain = random.choice(cls._domains) - domain = f"{rand}.{domain}" - if debug.logging: - print(f"AItianhuSpace | using domain: {domain}") - url = f"https://{domain}" - prompt = format_prompt(messages) - - with WebDriverSession(webdriver, "", headless=headless, proxy=proxy) as driver: - from selenium.webdriver.common.by import By - from selenium.webdriver.support.ui import WebDriverWait - from selenium.webdriver.support import expected_conditions as EC - - wait = WebDriverWait(driver, timeout) - - # Bypass devtools detection - driver.get("https://blank.page/") - wait.until(EC.visibility_of_element_located((By.ID, "sheet"))) - driver.execute_script(f""" - document.getElementById('sheet').addEventListener('click', () => {{ - window.open('{url}', '_blank'); - }}); - """) - driver.find_element(By.ID, "sheet").click() - time.sleep(10) - - original_window = driver.current_window_handle - for window_handle in driver.window_handles: - if window_handle != original_window: - driver.close() - driver.switch_to.window(window_handle) - break - - # Wait for page load - wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "textarea.n-input__textarea-el"))) - - # Register hook in XMLHttpRequest - script = """ -const _http_request_open = XMLHttpRequest.prototype.open; -window._last_message = window._message = ""; -window._loadend = false; -XMLHttpRequest.prototype.open = function(method, url) { - if (url == "/api/chat-process") { - this.addEventListener("progress", (event) => { - const lines = this.responseText.split("\\n"); - try { - window._message = JSON.parse(lines[lines.length-1])["text"]; - } catch(e) { } - }); - this.addEventListener("loadend", (event) => { - window._loadend = true; - }); - } - return _http_request_open.call(this, method, url); -} -""" - driver.execute_script(script) - - # Submit prompt - driver.find_element(By.CSS_SELECTOR, "textarea.n-input__textarea-el").send_keys(prompt) - driver.find_element(By.CSS_SELECTOR, "button.n-button.n-button--primary-type.n-button--medium-type").click() - - # Read response - while True: - chunk = driver.execute_script(""" -if (window._message && window._message != window._last_message) { - try { - return window._message.substring(window._last_message.length); - } finally { - window._last_message = window._message; - } -} -if (window._loadend) { - return null; -} -return ""; -""") - if chunk: - yield chunk - elif chunk != "": - break - else: - time.sleep(0.1) \ No newline at end of file diff --git a/g4f/Provider/Aichat.py b/g4f/Provider/Aichat.py deleted file mode 100644 index 41ea9a96..00000000 --- a/g4f/Provider/Aichat.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import annotations - -from aiohttp import ClientSession - -from ..typing import Messages -from .base_provider import AsyncProvider, format_prompt -from .helper import get_cookies -from ..requests import StreamSession - -class Aichat(AsyncProvider): - url = "https://chat-gpt.org/chat" - working = False - supports_gpt_35_turbo = True - - @staticmethod - async def create_async( - model: str, - messages: Messages, - proxy: str = None, **kwargs) -> str: - - cookies = get_cookies('chat-gpt.org') if not kwargs.get('cookies') else kwargs.get('cookies') - if not cookies: - raise RuntimeError( - "g4f.provider.Aichat requires cookies, [refresh https://chat-gpt.org on chrome]" - ) - - headers = { - 'authority': 'chat-gpt.org', - 'accept': '*/*', - 'accept-language': 'en,fr-FR;q=0.9,fr;q=0.8,es-ES;q=0.7,es;q=0.6,en-US;q=0.5,am;q=0.4,de;q=0.3', - 'content-type': 'application/json', - 'origin': 'https://chat-gpt.org', - 'referer': 'https://chat-gpt.org/chat', - 'sec-ch-ua': '"Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"', - 'sec-ch-ua-mobile': '?0', - 'sec-ch-ua-platform': '"macOS"', - 'sec-fetch-dest': 'empty', - 'sec-fetch-mode': 'cors', - 'sec-fetch-site': 'same-origin', - 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', - } - - async with StreamSession(headers=headers, - cookies=cookies, - timeout=6, - proxies={"https": proxy} if proxy else None, - impersonate="chrome110", verify=False) as session: - - json_data = { - "message": format_prompt(messages), - "temperature": kwargs.get('temperature', 0.5), - "presence_penalty": 0, - "top_p": kwargs.get('top_p', 1), - "frequency_penalty": 0, - } - - async with session.post("https://chat-gpt.org/api/text", - json=json_data) as response: - - response.raise_for_status() - result = await response.json() - - if not result['response']: - raise Exception(f"Error Response: {result}") - - return result["message"] diff --git a/g4f/Provider/Berlin.py b/g4f/Provider/Berlin.py deleted file mode 100644 index ac376fab..00000000 --- a/g4f/Provider/Berlin.py +++ /dev/null @@ -1,78 +0,0 @@ -from __future__ import annotations - -import secrets -import uuid -import json -from aiohttp import ClientSession - -from ..typing import AsyncResult, Messages -from .base_provider import AsyncGeneratorProvider -from .helper import format_prompt - - -class Berlin(AsyncGeneratorProvider): - url = "https://ai.berlin4h.top" - working = False - supports_gpt_35_turbo = True - _token = None - - @classmethod - async def create_async_generator( - cls, - model: str, - messages: Messages, - proxy: str = None, - **kwargs - ) -> AsyncResult: - if not model: - model = "gpt-3.5-turbo" - headers = { - "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0", - "Accept": "*/*", - "Accept-Language": "de,en-US;q=0.7,en;q=0.3", - "Accept-Encoding": "gzip, deflate, br", - "Referer": f"{cls.url}/", - "Content-Type": "application/json", - "Origin": cls.url, - "Alt-Used": "ai.berlin4h.top", - "Connection": "keep-alive", - "Sec-Fetch-Dest": "empty", - "Sec-Fetch-Mode": "cors", - "Sec-Fetch-Site": "same-origin", - "Pragma": "no-cache", - "Cache-Control": "no-cache", - "TE": "trailers", - } - async with ClientSession(headers=headers) as session: - if not cls._token: - data = { - "account": '免费使用GPT3.5模型@163.com', - "password": '659e945c2d004686bad1a75b708c962f' - } - async with session.post(f"{cls.url}/api/login", json=data, proxy=proxy) as response: - response.raise_for_status() - cls._token = (await response.json())["data"]["token"] - headers = { - "token": cls._token - } - prompt = format_prompt(messages) - data = { - "prompt": prompt, - "parentMessageId": str(uuid.uuid4()), - "options": { - "model": model, - "temperature": 0, - "presence_penalty": 0, - "frequency_penalty": 0, - "max_tokens": 1888, - **kwargs - }, - } - async with session.post(f"{cls.url}/api/chat/completions", json=data, proxy=proxy, headers=headers) as response: - response.raise_for_status() - async for chunk in response.content: - if chunk.strip(): - try: - yield json.loads(chunk)["content"] - except: - raise RuntimeError(f"Response: {chunk.decode()}") diff --git a/g4f/Provider/HuggingChat.py b/g4f/Provider/HuggingChat.py new file mode 100644 index 00000000..4a42b3c8 --- /dev/null +++ b/g4f/Provider/HuggingChat.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +import json, uuid + +from aiohttp import ClientSession + +from ..typing import AsyncResult, Messages +from .base_provider import AsyncGeneratorProvider +from .helper import format_prompt, get_cookies + +map = { + "openchat/openchat_3.5": "openchat/openchat-3.5-1210", +} + +class HuggingChat(AsyncGeneratorProvider): + url = "https://huggingface.co/chat" + working = True + model = "meta-llama/Llama-2-70b-chat-hf" + + @classmethod + async def create_async_generator( + cls, + model: str, + messages: Messages, + stream: bool = True, + proxy: str = None, + web_search: bool = False, + cookies: dict = None, + **kwargs + ) -> AsyncResult: + if not model: + model = cls.model + elif model in map: + model = map[model] + if not cookies: + cookies = get_cookies(".huggingface.co") + + 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', + } + async with ClientSession( + cookies=cookies, + headers=headers + ) as session: + async with session.post(f"{cls.url}/conversation", json={"model": model}, proxy=proxy) as response: + conversation_id = (await response.json())["conversationId"] + + send = { + "id": str(uuid.uuid4()), + "inputs": format_prompt(messages), + "is_retry": False, + "response_id": str(uuid.uuid4()), + "web_search": web_search + } + async with session.post(f"{cls.url}/conversation/{conversation_id}", json=send, proxy=proxy) as response: + first_token = True + async for line in response.content: + line = json.loads(line[:-1]) + if "type" not in line: + raise RuntimeError(f"Response: {line}") + elif line["type"] == "stream": + token = line["token"] + if first_token: + token = token.lstrip() + first_token = False + yield token + elif line["type"] == "finalAnswer": + break + + async with session.delete(f"{cls.url}/conversation/{conversation_id}", proxy=proxy) as response: + response.raise_for_status() diff --git a/g4f/Provider/MyShell.py b/g4f/Provider/MyShell.py deleted file mode 100644 index 145cc0bf..00000000 --- a/g4f/Provider/MyShell.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import annotations - -import time, json - -from ..typing import CreateResult, Messages -from .base_provider import AbstractProvider -from .helper import format_prompt -from ..webdriver import WebDriver, WebDriverSession, bypass_cloudflare - -class MyShell(AbstractProvider): - url = "https://app.myshell.ai/chat" - working = True - supports_gpt_35_turbo = True - supports_stream = True - - @classmethod - def create_completion( - cls, - model: str, - messages: Messages, - stream: bool, - proxy: str = None, - timeout: int = 120, - webdriver: WebDriver = None, - **kwargs - ) -> CreateResult: - with WebDriverSession(webdriver, "", proxy=proxy) as driver: - bypass_cloudflare(driver, cls.url, timeout) - - # Send request with message - data = { - "botId": "4738", - "conversation_scenario": 3, - "message": format_prompt(messages), - "messageType": 1 - } - script = """ -response = await fetch("https://api.myshell.ai/v1/bot/chat/send_message", { - "headers": { - "accept": "application/json", - "content-type": "application/json", - "myshell-service-name": "organics-api", - "visitor-id": localStorage.getItem("mix_visitorId") - }, - "body": '{body}', - "method": "POST" -}) -window._reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); -""" - driver.execute_script(script.replace("{body}", json.dumps(data))) - script = """ -chunk = await window._reader.read(); -if (chunk.done) { - return null; -} -content = ''; -chunk.value.split('\\n').forEach((line, index) => { - if (line.startsWith('data: ')) { - try { - const data = JSON.parse(line.substring('data: '.length)); - if ('content' in data) { - content += data['content']; - } - } catch(e) {} - } -}); -return content; -""" - while True: - chunk = driver.execute_script(script) - if chunk: - yield chunk - elif chunk != "": - break - else: - time.sleep(0.1) \ No newline at end of file diff --git a/g4f/Provider/Opchatgpts.py b/g4f/Provider/Opchatgpts.py deleted file mode 100644 index 8c2987fa..00000000 --- a/g4f/Provider/Opchatgpts.py +++ /dev/null @@ -1,59 +0,0 @@ -from __future__ import annotations - -import random, string, json -from aiohttp import ClientSession - -from ..typing import Messages, AsyncResult -from .base_provider import AsyncGeneratorProvider -from .helper import get_random_string - -class Opchatgpts(AsyncGeneratorProvider): - url = "https://opchatgpts.net" - working = False - supports_message_history = True - supports_gpt_35_turbo = True - - @classmethod - async def create_async_generator( - cls, - model: str, - messages: Messages, - proxy: str = None, **kwargs) -> AsyncResult: - - headers = { - "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", - "Accept" : "*/*", - "Accept-Language" : "de,en-US;q=0.7,en;q=0.3", - "Origin" : cls.url, - "Alt-Used" : "opchatgpts.net", - "Referer" : f"{cls.url}/chatgpt-free-use/", - "Sec-Fetch-Dest" : "empty", - "Sec-Fetch-Mode" : "cors", - "Sec-Fetch-Site" : "same-origin", - } - async with ClientSession( - headers=headers - ) as session: - data = { - "botId": "default", - "chatId": get_random_string(), - "contextId": 28, - "customId": None, - "messages": messages, - "newMessage": messages[-1]["content"], - "session": "N/A", - "stream": True - } - async with session.post(f"{cls.url}/wp-json/mwai-ui/v1/chats/submit", json=data, proxy=proxy) as response: - response.raise_for_status() - async for line in response.content: - if line.startswith(b"data: "): - try: - line = json.loads(line[6:]) - assert "type" in line - except: - raise RuntimeError(f"Broken line: {line.decode()}") - if line["type"] == "live": - yield line["data"] - elif line["type"] == "end": - break \ No newline at end of file diff --git a/g4f/Provider/PerplexityAi.py b/g4f/Provider/PerplexityAi.py deleted file mode 100644 index 023968dc..00000000 --- a/g4f/Provider/PerplexityAi.py +++ /dev/null @@ -1,106 +0,0 @@ -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 - -from ..typing import CreateResult, Messages -from .base_provider import AbstractProvider -from .helper import format_prompt -from ..webdriver import WebDriver, WebDriverSession - -class PerplexityAi(AbstractProvider): - url = "https://www.perplexity.ai" - working = True - supports_gpt_35_turbo = True - supports_stream = True - - @classmethod - def create_completion( - cls, - model: str, - messages: Messages, - stream: bool, - proxy: str = None, - timeout: int = 120, - webdriver: WebDriver = None, - virtual_display: bool = True, - copilot: bool = False, - **kwargs - ) -> CreateResult: - with WebDriverSession(webdriver, "", virtual_display=virtual_display, proxy=proxy) as driver: - prompt = format_prompt(messages) - - driver.get(f"{cls.url}/") - wait = WebDriverWait(driver, timeout) - - # Is page loaded? - wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "textarea[placeholder='Ask anything...']"))) - - # Register WebSocket hook - script = """ -window._message = window._last_message = ""; -window._message_finished = false; -const _socket_send = WebSocket.prototype.send; -WebSocket.prototype.send = function(...args) { - if (!window.socket_onmessage) { - window._socket_onmessage = this; - this.addEventListener("message", (event) => { - if (event.data.startsWith("42")) { - let data = JSON.parse(event.data.substring(2)); - if (data[0] =="query_progress" || data[0] == "query_answered") { - let content = JSON.parse(data[1]["text"]); - if (data[1]["mode"] == "copilot") { - content = content[content.length-1]["content"]["answer"]; - content = JSON.parse(content); - } - window._message = content["answer"]; - if (!window._message_finished) { - window._message_finished = data[0] == "query_answered"; - } - } - } - }); - } - return _socket_send.call(this, ...args); -}; -""" - driver.execute_script(script) - - if copilot: - try: - # Check for account - driver.find_element(By.CSS_SELECTOR, "img[alt='User avatar']") - # Enable copilot - driver.find_element(By.CSS_SELECTOR, "button[data-testid='copilot-toggle']").click() - except: - raise RuntimeError("You need a account for copilot") - - # Submit prompt - driver.find_element(By.CSS_SELECTOR, "textarea[placeholder='Ask anything...']").send_keys(prompt) - driver.find_element(By.CSS_SELECTOR, "textarea[placeholder='Ask anything...']").send_keys(Keys.ENTER) - - # Stream response - script = """ -if(window._message && window._message != window._last_message) { - try { - return window._message.substring(window._last_message.length); - } finally { - window._last_message = window._message; - } -} else if(window._message_finished) { - return null; -} else { - return ''; -} -""" - while True: - chunk = driver.execute_script(script) - if chunk: - yield chunk - elif chunk != "": - break - else: - time.sleep(0.1) \ No newline at end of file diff --git a/g4f/Provider/TalkAi.py b/g4f/Provider/TalkAi.py deleted file mode 100644 index d4efd269..00000000 --- a/g4f/Provider/TalkAi.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import annotations - -import time, json, time - -from ..typing import CreateResult, Messages -from .base_provider import AbstractProvider -from ..webdriver import WebDriver, WebDriverSession - -class TalkAi(AbstractProvider): - url = "https://talkai.info" - working = True - supports_gpt_35_turbo = True - supports_stream = True - - @classmethod - def create_completion( - cls, - model: str, - messages: Messages, - stream: bool, - proxy: str = None, - webdriver: WebDriver = None, - **kwargs - ) -> CreateResult: - with WebDriverSession(webdriver, "", virtual_display=True, proxy=proxy) as driver: - 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(f"{cls.url}/chat/") - - # Wait for page load - WebDriverWait(driver, 240).until( - EC.presence_of_element_located((By.CSS_SELECTOR, "body.chat-page")) - ) - - data = { - "type": "chat", - "message": messages[-1]["content"], - "messagesHistory": [{ - "from": "you" if message["role"] == "user" else "chatGPT", - "content": message["content"] - } for message in messages], - "model": model if model else "gpt-3.5-turbo", - "max_tokens": 256, - "temperature": 1, - "top_p": 1, - "presence_penalty": 0, - "frequency_penalty": 0, - **kwargs - } - script = """ -const response = await fetch("/chat/send2/", { - "headers": { - "Accept": "application/json", - "Content-Type": "application/json", - }, - "body": {body}, - "method": "POST" -}); -window._reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); -""" - driver.execute_script( - script.replace("{body}", json.dumps(json.dumps(data))) - ) - # Read response - while True: - chunk = driver.execute_script(""" -chunk = await window._reader.read(); -if (chunk["done"]) { - return null; -} -content = ""; -lines = chunk["value"].split("\\n") -lines.forEach((line, index) => { - if (line.startsWith('data: ')) { - content += line.substring('data: '.length); - } -}); -return content; -""") - if chunk: - yield chunk.replace("\\n", "\n") - elif chunk != "": - break - else: - time.sleep(0.1) \ No newline at end of file diff --git a/g4f/Provider/Yqcloud.py b/g4f/Provider/Yqcloud.py deleted file mode 100644 index 2829c5bf..00000000 --- a/g4f/Provider/Yqcloud.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import annotations - -import random -from ..requests import StreamSession - -from ..typing import AsyncResult, Messages -from .base_provider import AsyncGeneratorProvider, format_prompt - - -class Yqcloud(AsyncGeneratorProvider): - url = "https://chat9.yqcloud.top/" - working = True - supports_gpt_35_turbo = True - - @staticmethod - async def create_async_generator( - model: str, - messages: Messages, - proxy: str = None, - timeout: int = 120, - **kwargs, - ) -> AsyncResult: - async with StreamSession( - headers=_create_header(), proxies={"https": proxy}, timeout=timeout - ) as session: - payload = _create_payload(messages, **kwargs) - async with session.post("https://api.aichatos.cloud/api/generateStream", json=payload) as response: - response.raise_for_status() - async for chunk in response.iter_content(): - if chunk: - chunk = chunk.decode() - if "sorry, 您的ip已由于触发防滥用检测而被封禁" in chunk: - raise RuntimeError("IP address is blocked by abuse detection.") - yield chunk - - -def _create_header(): - return { - "accept" : "application/json, text/plain, */*", - "content-type" : "application/json", - "origin" : "https://chat9.yqcloud.top", - "referer" : "https://chat9.yqcloud.top/" - } - - -def _create_payload( - messages: Messages, - system_message: str = "", - user_id: int = None, - **kwargs -): - if not user_id: - user_id = random.randint(1690000544336, 2093025544336) - return { - "prompt": format_prompt(messages), - "network": True, - "system": system_message, - "withoutContext": False, - "stream": True, - "userId": f"#/chat/{user_id}" - } diff --git a/g4f/Provider/__init__.py b/g4f/Provider/__init__.py index 7a3dbb76..ee8d2c1b 100644 --- a/g4f/Provider/__init__.py +++ b/g4f/Provider/__init__.py @@ -11,11 +11,8 @@ from .selenium import * from .Aura import Aura from .AiAsk import AiAsk -from .Aichat import Aichat from .AiChatOnline import AiChatOnline from .AItianhu import AItianhu -from .AItianhuSpace import AItianhuSpace -from .Berlin import Berlin from .Bing import Bing from .ChatAnywhere import ChatAnywhere from .ChatBase import ChatBase @@ -43,20 +40,16 @@ from .GptGo import GptGo from .GptGod import GptGod from .GptTalkRu import GptTalkRu from .Hashnode import Hashnode +from .HuggingChat import HuggingChat from .Koala import Koala from .Liaobots import Liaobots from .Llama2 import Llama2 -from .MyShell import MyShell from .OnlineGpt import OnlineGpt -from .Opchatgpts import Opchatgpts -from .PerplexityAi import PerplexityAi from .Phind import Phind from .Pi import Pi -from .TalkAi import TalkAi from .Vercel import Vercel from .Ylokh import Ylokh from .You import You -from .Yqcloud import Yqcloud from .Bestim import Bestim import sys diff --git a/g4f/Provider/bing/create_images.py b/g4f/Provider/bing/create_images.py index 060cd184..288a3d90 100644 --- a/g4f/Provider/bing/create_images.py +++ b/g4f/Provider/bing/create_images.py @@ -13,10 +13,10 @@ from urllib.parse import quote from typing import Generator, List, Dict from ..create_images import CreateImagesProvider -from ..helper import get_cookies, get_event_loop +from ..helper import get_cookies from ...webdriver import WebDriver, get_driver_cookies, get_browser from ...base_provider import ProviderType -from ...image import format_images_markdown +from ...image import ImageResponse BING_URL = "https://www.bing.com" TIMEOUT_LOGIN = 1200 @@ -161,23 +161,7 @@ def read_images(html_content: str) -> List[str]: raise RuntimeError("No images found") return images -async def create_images_markdown(cookies: Dict[str, str], prompt: str, proxy: str = None) -> str: - """ - Creates markdown formatted string with images based on the prompt. - - Args: - cookies (Dict[str, str]): Cookies to be used for the session. - prompt (str): Prompt to generate images. - proxy (str, optional): Proxy configuration. - - Returns: - str: Markdown formatted string with images. - """ - async with create_session(cookies) as session: - images = await create_images(session, prompt, proxy) - return format_images_markdown(images, prompt) - -def get_cookies_from_browser(proxy: str = None) -> Dict[str, str]: +def get_cookies_from_browser(proxy: str = None) -> dict[str, str]: """ Retrieves cookies from the browser using webdriver. @@ -185,7 +169,7 @@ def get_cookies_from_browser(proxy: str = None) -> Dict[str, str]: proxy (str, optional): Proxy configuration. Returns: - Dict[str, str]: Retrieved cookies. + dict[str, str]: Retrieved cookies. """ with get_browser(proxy=proxy) as driver: wait_for_login(driver) @@ -194,48 +178,47 @@ def get_cookies_from_browser(proxy: str = None) -> Dict[str, str]: class CreateImagesBing: """A class for creating images using Bing.""" - - _cookies: Dict[str, str] = {} - @classmethod - def create_completion(cls, prompt: str, cookies: Dict[str, str] = None, proxy: str = None) -> Generator[str, None, None]: + def __init__(self, cookies: dict[str, str] = {}, proxy: str = None) -> None: + self.cookies = cookies + self.proxy = proxy + + def create_completion(self, prompt: str) -> Generator[ImageResponse, None, None]: """ Generator for creating imagecompletion based on a prompt. Args: prompt (str): Prompt to generate images. - cookies (Dict[str, str], optional): Cookies for the session. If None, cookies are retrieved automatically. - proxy (str, optional): Proxy configuration. Yields: Generator[str, None, None]: The final output as markdown formatted string with images. """ - loop = get_event_loop() - cookies = cookies or cls._cookies or get_cookies(".bing.com") + cookies = self.cookies or get_cookies(".bing.com") if "_U" not in cookies: login_url = os.environ.get("G4F_LOGIN_URL") if login_url: yield f"Please login: [Bing]({login_url})\n\n" - cls._cookies = cookies = get_cookies_from_browser(proxy) - yield loop.run_until_complete(create_images_markdown(cookies, prompt, proxy)) + self.cookies = get_cookies_from_browser(self.proxy) + yield asyncio.run(self.create_async(prompt)) - @classmethod - async def create_async(cls, prompt: str, cookies: Dict[str, str] = None, proxy: str = None) -> str: + async def create_async(self, prompt: str) -> ImageResponse: """ Asynchronously creates a markdown formatted string with images based on the prompt. Args: prompt (str): Prompt to generate images. - cookies (Dict[str, str], optional): Cookies for the session. If None, cookies are retrieved automatically. - proxy (str, optional): Proxy configuration. Returns: str: Markdown formatted string with images. """ - cookies = cookies or cls._cookies or get_cookies(".bing.com") + cookies = self.cookies or get_cookies(".bing.com") if "_U" not in cookies: - cls._cookies = cookies = get_cookies_from_browser(proxy) - return await create_images_markdown(cookies, prompt, proxy) + raise RuntimeError('"_U" cookie is missing') + async with create_session(cookies) as session: + images = await create_images(session, prompt, self.proxy) + return ImageResponse(images, prompt) + +service = CreateImagesBing() def patch_provider(provider: ProviderType) -> CreateImagesProvider: """ @@ -247,4 +230,8 @@ def patch_provider(provider: ProviderType) -> CreateImagesProvider: Returns: CreateImagesProvider: The patched provider with image creation capabilities. """ - return CreateImagesProvider(provider, CreateImagesBing.create_completion, CreateImagesBing.create_async) \ No newline at end of file + return CreateImagesProvider( + provider, + service.create_completion, + service.create_async + ) \ No newline at end of file diff --git a/g4f/Provider/deprecated/Aichat.py b/g4f/Provider/deprecated/Aichat.py new file mode 100644 index 00000000..68c9c546 --- /dev/null +++ b/g4f/Provider/deprecated/Aichat.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from ...typing import Messages +from ..base_provider import AsyncProvider, format_prompt +from ..helper import get_cookies +from ...requests import StreamSession + +class Aichat(AsyncProvider): + url = "https://chat-gpt.org/chat" + working = False + supports_gpt_35_turbo = True + + @staticmethod + async def create_async( + model: str, + messages: Messages, + proxy: str = None, **kwargs) -> str: + + cookies = get_cookies('chat-gpt.org') if not kwargs.get('cookies') else kwargs.get('cookies') + if not cookies: + raise RuntimeError( + "g4f.provider.Aichat requires cookies, [refresh https://chat-gpt.org on chrome]" + ) + + headers = { + 'authority': 'chat-gpt.org', + 'accept': '*/*', + 'accept-language': 'en,fr-FR;q=0.9,fr;q=0.8,es-ES;q=0.7,es;q=0.6,en-US;q=0.5,am;q=0.4,de;q=0.3', + 'content-type': 'application/json', + 'origin': 'https://chat-gpt.org', + 'referer': 'https://chat-gpt.org/chat', + 'sec-ch-ua': '"Chromium";v="118", "Google Chrome";v="118", "Not=A?Brand";v="99"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"macOS"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-origin', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', + } + + async with StreamSession(headers=headers, + cookies=cookies, + timeout=6, + proxies={"https": proxy} if proxy else None, + impersonate="chrome110", verify=False) as session: + + json_data = { + "message": format_prompt(messages), + "temperature": kwargs.get('temperature', 0.5), + "presence_penalty": 0, + "top_p": kwargs.get('top_p', 1), + "frequency_penalty": 0, + } + + async with session.post("https://chat-gpt.org/api/text", + json=json_data) as response: + + response.raise_for_status() + result = await response.json() + + if not result['response']: + raise Exception(f"Error Response: {result}") + + return result["message"] diff --git a/g4f/Provider/deprecated/Berlin.py b/g4f/Provider/deprecated/Berlin.py new file mode 100644 index 00000000..5e81705a --- /dev/null +++ b/g4f/Provider/deprecated/Berlin.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +import secrets +import uuid +import json +from aiohttp import ClientSession + +from ...typing import AsyncResult, Messages +from ..base_provider import AsyncGeneratorProvider +from ..helper import format_prompt + + +class Berlin(AsyncGeneratorProvider): + url = "https://ai.berlin4h.top" + working = False + supports_gpt_35_turbo = True + _token = None + + @classmethod + async def create_async_generator( + cls, + model: str, + messages: Messages, + proxy: str = None, + **kwargs + ) -> AsyncResult: + if not model: + model = "gpt-3.5-turbo" + headers = { + "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0", + "Accept": "*/*", + "Accept-Language": "de,en-US;q=0.7,en;q=0.3", + "Accept-Encoding": "gzip, deflate, br", + "Referer": f"{cls.url}/", + "Content-Type": "application/json", + "Origin": cls.url, + "Alt-Used": "ai.berlin4h.top", + "Connection": "keep-alive", + "Sec-Fetch-Dest": "empty", + "Sec-Fetch-Mode": "cors", + "Sec-Fetch-Site": "same-origin", + "Pragma": "no-cache", + "Cache-Control": "no-cache", + "TE": "trailers", + } + async with ClientSession(headers=headers) as session: + if not cls._token: + data = { + "account": '免费使用GPT3.5模型@163.com', + "password": '659e945c2d004686bad1a75b708c962f' + } + async with session.post(f"{cls.url}/api/login", json=data, proxy=proxy) as response: + response.raise_for_status() + cls._token = (await response.json())["data"]["token"] + headers = { + "token": cls._token + } + prompt = format_prompt(messages) + data = { + "prompt": prompt, + "parentMessageId": str(uuid.uuid4()), + "options": { + "model": model, + "temperature": 0, + "presence_penalty": 0, + "frequency_penalty": 0, + "max_tokens": 1888, + **kwargs + }, + } + async with session.post(f"{cls.url}/api/chat/completions", json=data, proxy=proxy, headers=headers) as response: + response.raise_for_status() + async for chunk in response.content: + if chunk.strip(): + try: + yield json.loads(chunk)["content"] + except: + raise RuntimeError(f"Response: {chunk.decode()}") diff --git a/g4f/Provider/deprecated/Opchatgpts.py b/g4f/Provider/deprecated/Opchatgpts.py new file mode 100644 index 00000000..94b1d099 --- /dev/null +++ b/g4f/Provider/deprecated/Opchatgpts.py @@ -0,0 +1,59 @@ +from __future__ import annotations + +import random, string, json +from aiohttp import ClientSession + +from ...typing import Messages, AsyncResult +from ..base_provider import AsyncGeneratorProvider +from ..helper import get_random_string + +class Opchatgpts(AsyncGeneratorProvider): + url = "https://opchatgpts.net" + working = False + supports_message_history = True + supports_gpt_35_turbo = True + + @classmethod + async def create_async_generator( + cls, + model: str, + messages: Messages, + proxy: str = None, **kwargs) -> AsyncResult: + + headers = { + "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", + "Accept" : "*/*", + "Accept-Language" : "de,en-US;q=0.7,en;q=0.3", + "Origin" : cls.url, + "Alt-Used" : "opchatgpts.net", + "Referer" : f"{cls.url}/chatgpt-free-use/", + "Sec-Fetch-Dest" : "empty", + "Sec-Fetch-Mode" : "cors", + "Sec-Fetch-Site" : "same-origin", + } + async with ClientSession( + headers=headers + ) as session: + data = { + "botId": "default", + "chatId": get_random_string(), + "contextId": 28, + "customId": None, + "messages": messages, + "newMessage": messages[-1]["content"], + "session": "N/A", + "stream": True + } + async with session.post(f"{cls.url}/wp-json/mwai-ui/v1/chats/submit", json=data, proxy=proxy) as response: + response.raise_for_status() + async for line in response.content: + if line.startswith(b"data: "): + try: + line = json.loads(line[6:]) + assert "type" in line + except: + raise RuntimeError(f"Broken line: {line.decode()}") + if line["type"] == "live": + yield line["data"] + elif line["type"] == "end": + break \ No newline at end of file diff --git a/g4f/Provider/deprecated/Yqcloud.py b/g4f/Provider/deprecated/Yqcloud.py new file mode 100644 index 00000000..2ec6931a --- /dev/null +++ b/g4f/Provider/deprecated/Yqcloud.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +import random +from ...requests import StreamSession + +from ...typing import AsyncResult, Messages +from ..base_provider import AsyncGeneratorProvider, format_prompt + + +class Yqcloud(AsyncGeneratorProvider): + url = "https://chat9.yqcloud.top/" + working = True + supports_gpt_35_turbo = True + + @staticmethod + async def create_async_generator( + model: str, + messages: Messages, + proxy: str = None, + timeout: int = 120, + **kwargs, + ) -> AsyncResult: + async with StreamSession( + headers=_create_header(), proxies={"https": proxy}, timeout=timeout + ) as session: + payload = _create_payload(messages, **kwargs) + async with session.post("https://api.aichatos.cloud/api/generateStream", json=payload) as response: + response.raise_for_status() + async for chunk in response.iter_content(): + if chunk: + chunk = chunk.decode() + if "sorry, 您的ip已由于触发防滥用检测而被封禁" in chunk: + raise RuntimeError("IP address is blocked by abuse detection.") + yield chunk + + +def _create_header(): + return { + "accept" : "application/json, text/plain, */*", + "content-type" : "application/json", + "origin" : "https://chat9.yqcloud.top", + "referer" : "https://chat9.yqcloud.top/" + } + + +def _create_payload( + messages: Messages, + system_message: str = "", + user_id: int = None, + **kwargs +): + if not user_id: + user_id = random.randint(1690000544336, 2093025544336) + return { + "prompt": format_prompt(messages), + "network": True, + "system": system_message, + "withoutContext": False, + "stream": True, + "userId": f"#/chat/{user_id}" + } diff --git a/g4f/Provider/deprecated/__init__.py b/g4f/Provider/deprecated/__init__.py index ca5ac83e..4d7eb5da 100644 --- a/g4f/Provider/deprecated/__init__.py +++ b/g4f/Provider/deprecated/__init__.py @@ -18,4 +18,8 @@ from .Acytoo import Acytoo from .Aibn import Aibn from .Ails import Ails from .ChatgptDuo import ChatgptDuo -from .Cromicle import Cromicle \ No newline at end of file +from .Cromicle import Cromicle +from .Opchatgpts import Opchatgpts +from .Yqcloud import Yqcloud +from .Aichat import Aichat +from .Berlin import Berlin \ No newline at end of file diff --git a/g4f/Provider/needs_auth/HuggingChat.py b/g4f/Provider/needs_auth/HuggingChat.py deleted file mode 100644 index e4fa237d..00000000 --- a/g4f/Provider/needs_auth/HuggingChat.py +++ /dev/null @@ -1,71 +0,0 @@ -from __future__ import annotations - -import json, uuid - -from aiohttp import ClientSession - -from ...typing import AsyncResult, Messages -from ..base_provider import AsyncGeneratorProvider -from ..helper import format_prompt, get_cookies - -map = { - "openchat/openchat_3.5": "openchat/openchat-3.5-1210", -} - -class HuggingChat(AsyncGeneratorProvider): - url = "https://huggingface.co/chat" - working = True - model = "meta-llama/Llama-2-70b-chat-hf" - - @classmethod - async def create_async_generator( - cls, - model: str, - messages: Messages, - stream: bool = True, - proxy: str = None, - web_search: bool = False, - cookies: dict = None, - **kwargs - ) -> AsyncResult: - if not model: - model = cls.model - elif model in map: - model = map[model] - if not cookies: - cookies = get_cookies(".huggingface.co") - - 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', - } - async with ClientSession( - cookies=cookies, - headers=headers - ) as session: - async with session.post(f"{cls.url}/conversation", json={"model": model}, proxy=proxy) as response: - conversation_id = (await response.json())["conversationId"] - - send = { - "id": str(uuid.uuid4()), - "inputs": format_prompt(messages), - "is_retry": False, - "response_id": str(uuid.uuid4()), - "web_search": web_search - } - async with session.post(f"{cls.url}/conversation/{conversation_id}", json=send, proxy=proxy) as response: - first_token = True - async for line in response.content: - line = json.loads(line[:-1]) - if "type" not in line: - raise RuntimeError(f"Response: {line}") - elif line["type"] == "stream": - token = line["token"] - if first_token: - token = token.lstrip() - first_token = False - yield token - elif line["type"] == "finalAnswer": - break - - async with session.delete(f"{cls.url}/conversation/{conversation_id}", proxy=proxy) as response: - response.raise_for_status() diff --git a/g4f/Provider/needs_auth/__init__.py b/g4f/Provider/needs_auth/__init__.py index b85cd36a..46e1f740 100644 --- a/g4f/Provider/needs_auth/__init__.py +++ b/g4f/Provider/needs_auth/__init__.py @@ -2,7 +2,6 @@ from .Bard import Bard from .Raycast import Raycast from .Theb import Theb from .ThebApi import ThebApi -from .HuggingChat import HuggingChat from .OpenaiChat import OpenaiChat from .OpenAssistant import OpenAssistant from .Poe import Poe \ No newline at end of file diff --git a/g4f/Provider/selenium/AItianhuSpace.py b/g4f/Provider/selenium/AItianhuSpace.py new file mode 100644 index 00000000..9878bd5a --- /dev/null +++ b/g4f/Provider/selenium/AItianhuSpace.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +import time +import random + +from ...typing import CreateResult, Messages +from ..base_provider import AbstractProvider +from ..helper import format_prompt, get_random_string +from ...webdriver import WebDriver, WebDriverSession +from ... import debug + +class AItianhuSpace(AbstractProvider): + url = "https://chat3.aiyunos.top/" + working = True + supports_stream = True + supports_gpt_35_turbo = True + _domains = ["aitianhu.com", "aitianhu1.top"] + + @classmethod + def create_completion( + cls, + model: str, + messages: Messages, + stream: bool, + domain: str = None, + proxy: str = None, + timeout: int = 120, + webdriver: WebDriver = None, + headless: bool = True, + **kwargs + ) -> CreateResult: + if not model: + model = "gpt-3.5-turbo" + if not domain: + rand = get_random_string(6) + domain = random.choice(cls._domains) + domain = f"{rand}.{domain}" + if debug.logging: + print(f"AItianhuSpace | using domain: {domain}") + url = f"https://{domain}" + prompt = format_prompt(messages) + + with WebDriverSession(webdriver, "", headless=headless, proxy=proxy) as driver: + from selenium.webdriver.common.by import By + from selenium.webdriver.support.ui import WebDriverWait + from selenium.webdriver.support import expected_conditions as EC + + wait = WebDriverWait(driver, timeout) + + # Bypass devtools detection + driver.get("https://blank.page/") + wait.until(EC.visibility_of_element_located((By.ID, "sheet"))) + driver.execute_script(f""" + document.getElementById('sheet').addEventListener('click', () => {{ + window.open('{url}', '_blank'); + }}); + """) + driver.find_element(By.ID, "sheet").click() + time.sleep(10) + + original_window = driver.current_window_handle + for window_handle in driver.window_handles: + if window_handle != original_window: + driver.close() + driver.switch_to.window(window_handle) + break + + # Wait for page load + wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "textarea.n-input__textarea-el"))) + + # Register hook in XMLHttpRequest + script = """ +const _http_request_open = XMLHttpRequest.prototype.open; +window._last_message = window._message = ""; +window._loadend = false; +XMLHttpRequest.prototype.open = function(method, url) { + if (url == "/api/chat-process") { + this.addEventListener("progress", (event) => { + const lines = this.responseText.split("\\n"); + try { + window._message = JSON.parse(lines[lines.length-1])["text"]; + } catch(e) { } + }); + this.addEventListener("loadend", (event) => { + window._loadend = true; + }); + } + return _http_request_open.call(this, method, url); +} +""" + driver.execute_script(script) + + # Submit prompt + driver.find_element(By.CSS_SELECTOR, "textarea.n-input__textarea-el").send_keys(prompt) + driver.find_element(By.CSS_SELECTOR, "button.n-button.n-button--primary-type.n-button--medium-type").click() + + # Read response + while True: + chunk = driver.execute_script(""" +if (window._message && window._message != window._last_message) { + try { + return window._message.substring(window._last_message.length); + } finally { + window._last_message = window._message; + } +} +if (window._loadend) { + return null; +} +return ""; +""") + if chunk: + yield chunk + elif chunk != "": + break + else: + time.sleep(0.1) \ No newline at end of file diff --git a/g4f/Provider/selenium/MyShell.py b/g4f/Provider/selenium/MyShell.py new file mode 100644 index 00000000..a3f246ff --- /dev/null +++ b/g4f/Provider/selenium/MyShell.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +import time, json + +from ...typing import CreateResult, Messages +from ..base_provider import AbstractProvider +from ..helper import format_prompt +from ...webdriver import WebDriver, WebDriverSession, bypass_cloudflare + +class MyShell(AbstractProvider): + url = "https://app.myshell.ai/chat" + working = True + supports_gpt_35_turbo = True + supports_stream = True + + @classmethod + def create_completion( + cls, + model: str, + messages: Messages, + stream: bool, + proxy: str = None, + timeout: int = 120, + webdriver: WebDriver = None, + **kwargs + ) -> CreateResult: + with WebDriverSession(webdriver, "", proxy=proxy) as driver: + bypass_cloudflare(driver, cls.url, timeout) + + # Send request with message + data = { + "botId": "4738", + "conversation_scenario": 3, + "message": format_prompt(messages), + "messageType": 1 + } + script = """ +response = await fetch("https://api.myshell.ai/v1/bot/chat/send_message", { + "headers": { + "accept": "application/json", + "content-type": "application/json", + "myshell-service-name": "organics-api", + "visitor-id": localStorage.getItem("mix_visitorId") + }, + "body": '{body}', + "method": "POST" +}) +window._reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); +""" + driver.execute_script(script.replace("{body}", json.dumps(data))) + script = """ +chunk = await window._reader.read(); +if (chunk.done) { + return null; +} +content = ''; +chunk.value.split('\\n').forEach((line, index) => { + if (line.startsWith('data: ')) { + try { + const data = JSON.parse(line.substring('data: '.length)); + if ('content' in data) { + content += data['content']; + } + } catch(e) {} + } +}); +return content; +""" + while True: + chunk = driver.execute_script(script) + if chunk: + yield chunk + elif chunk != "": + break + else: + time.sleep(0.1) \ No newline at end of file diff --git a/g4f/Provider/selenium/PerplexityAi.py b/g4f/Provider/selenium/PerplexityAi.py new file mode 100644 index 00000000..4796f709 --- /dev/null +++ b/g4f/Provider/selenium/PerplexityAi.py @@ -0,0 +1,106 @@ +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 + +from ...typing import CreateResult, Messages +from ..base_provider import AbstractProvider +from ..helper import format_prompt +from ...webdriver import WebDriver, WebDriverSession + +class PerplexityAi(AbstractProvider): + url = "https://www.perplexity.ai" + working = True + supports_gpt_35_turbo = True + supports_stream = True + + @classmethod + def create_completion( + cls, + model: str, + messages: Messages, + stream: bool, + proxy: str = None, + timeout: int = 120, + webdriver: WebDriver = None, + virtual_display: bool = True, + copilot: bool = False, + **kwargs + ) -> CreateResult: + with WebDriverSession(webdriver, "", virtual_display=virtual_display, proxy=proxy) as driver: + prompt = format_prompt(messages) + + driver.get(f"{cls.url}/") + wait = WebDriverWait(driver, timeout) + + # Is page loaded? + wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "textarea[placeholder='Ask anything...']"))) + + # Register WebSocket hook + script = """ +window._message = window._last_message = ""; +window._message_finished = false; +const _socket_send = WebSocket.prototype.send; +WebSocket.prototype.send = function(...args) { + if (!window.socket_onmessage) { + window._socket_onmessage = this; + this.addEventListener("message", (event) => { + if (event.data.startsWith("42")) { + let data = JSON.parse(event.data.substring(2)); + if (data[0] =="query_progress" || data[0] == "query_answered") { + let content = JSON.parse(data[1]["text"]); + if (data[1]["mode"] == "copilot") { + content = content[content.length-1]["content"]["answer"]; + content = JSON.parse(content); + } + window._message = content["answer"]; + if (!window._message_finished) { + window._message_finished = data[0] == "query_answered"; + } + } + } + }); + } + return _socket_send.call(this, ...args); +}; +""" + driver.execute_script(script) + + if copilot: + try: + # Check for account + driver.find_element(By.CSS_SELECTOR, "img[alt='User avatar']") + # Enable copilot + driver.find_element(By.CSS_SELECTOR, "button[data-testid='copilot-toggle']").click() + except: + raise RuntimeError("You need a account for copilot") + + # Submit prompt + driver.find_element(By.CSS_SELECTOR, "textarea[placeholder='Ask anything...']").send_keys(prompt) + driver.find_element(By.CSS_SELECTOR, "textarea[placeholder='Ask anything...']").send_keys(Keys.ENTER) + + # Stream response + script = """ +if(window._message && window._message != window._last_message) { + try { + return window._message.substring(window._last_message.length); + } finally { + window._last_message = window._message; + } +} else if(window._message_finished) { + return null; +} else { + return ''; +} +""" + while True: + chunk = driver.execute_script(script) + if chunk: + yield chunk + elif chunk != "": + break + else: + time.sleep(0.1) \ No newline at end of file diff --git a/g4f/Provider/selenium/TalkAi.py b/g4f/Provider/selenium/TalkAi.py new file mode 100644 index 00000000..5aeb48ac --- /dev/null +++ b/g4f/Provider/selenium/TalkAi.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +import time, json, time + +from ...typing import CreateResult, Messages +from ..base_provider import AbstractProvider +from ...webdriver import WebDriver, WebDriverSession + +class TalkAi(AbstractProvider): + url = "https://talkai.info" + working = True + supports_gpt_35_turbo = True + supports_stream = True + + @classmethod + def create_completion( + cls, + model: str, + messages: Messages, + stream: bool, + proxy: str = None, + webdriver: WebDriver = None, + **kwargs + ) -> CreateResult: + with WebDriverSession(webdriver, "", virtual_display=True, proxy=proxy) as driver: + 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(f"{cls.url}/chat/") + + # Wait for page load + WebDriverWait(driver, 240).until( + EC.presence_of_element_located((By.CSS_SELECTOR, "body.chat-page")) + ) + + data = { + "type": "chat", + "message": messages[-1]["content"], + "messagesHistory": [{ + "from": "you" if message["role"] == "user" else "chatGPT", + "content": message["content"] + } for message in messages], + "model": model if model else "gpt-3.5-turbo", + "max_tokens": 256, + "temperature": 1, + "top_p": 1, + "presence_penalty": 0, + "frequency_penalty": 0, + **kwargs + } + script = """ +const response = await fetch("/chat/send2/", { + "headers": { + "Accept": "application/json", + "Content-Type": "application/json", + }, + "body": {body}, + "method": "POST" +}); +window._reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); +""" + driver.execute_script( + script.replace("{body}", json.dumps(json.dumps(data))) + ) + # Read response + while True: + chunk = driver.execute_script(""" +chunk = await window._reader.read(); +if (chunk["done"]) { + return null; +} +content = ""; +lines = chunk["value"].split("\\n") +lines.forEach((line, index) => { + if (line.startsWith('data: ')) { + content += line.substring('data: '.length); + } +}); +return content; +""") + if chunk: + yield chunk.replace("\\n", "\n") + elif chunk != "": + break + else: + time.sleep(0.1) \ No newline at end of file diff --git a/g4f/Provider/selenium/__init__.py b/g4f/Provider/selenium/__init__.py index 80c48d14..a8c18a49 100644 --- a/g4f/Provider/selenium/__init__.py +++ b/g4f/Provider/selenium/__init__.py @@ -1 +1,5 @@ -from .Phind import Phind \ No newline at end of file +from .AItianhuSpace import AItianhuSpace +from .MyShell import MyShell +from .PerplexityAi import PerplexityAi +from .Phind import Phind +from .TalkAi import TalkAi \ No newline at end of file -- cgit v1.2.3