From 0b5d1d3d18736899d5665af846a2eb88873bc8f0 Mon Sep 17 00:00:00 2001 From: Bagus Indrayana Date: Thu, 17 Aug 2023 23:36:33 +0800 Subject: add provider --- g4f/Provider/Wuguokai.py | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ g4f/Provider/__init__.py | 4 ++- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 g4f/Provider/Wuguokai.py diff --git a/g4f/Provider/Wuguokai.py b/g4f/Provider/Wuguokai.py new file mode 100644 index 00000000..906283ad --- /dev/null +++ b/g4f/Provider/Wuguokai.py @@ -0,0 +1,65 @@ +import random, requests, json +from ..typing import Any, CreateResult +from .base_provider import BaseProvider + + +class Wuguokai(BaseProvider): + url = 'https://chat.wuguokai.xyz' + supports_gpt_35_turbo = True + supports_stream = False + needs_auth = False + working = True + + @staticmethod + def create_completion( + model: str, + messages: list[dict[str, str]], + stream: bool, + **kwargs: Any, + ) -> CreateResult: + base = '' + for message in messages: + base += '%s: %s\n' % (message['role'], message['content']) + base += 'assistant:' + + headers = { + 'authority': 'ai-api.wuguokai.xyz', + 'accept': 'application/json, text/plain, */*', + 'accept-language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7', + 'content-type': 'application/json', + 'origin': 'https://chat.wuguokai.xyz', + 'referer': 'https://chat.wuguokai.xyz/', + 'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"Windows"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-site', + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' + } + data ={ + "prompt": base, + "options": {}, + "userId": f"#/chat/{random.randint(1,99999999)}", + "usingContext": True + } + response = requests.post("https://ai-api20.wuguokai.xyz/api/chat-process", headers=headers, data=json.dumps(data),proxies=kwargs['proxy'] if 'proxy' in kwargs else {}) + _split = response.text.split("> 若回答失败请重试或多刷新几次界面后重试") + if response.status_code == 200: + if len(_split) > 1: + yield _split[1].strip() + else: + yield _split[0].strip() + else: + raise Exception(f"Error: {response.status_code} {response.reason}") + + @classmethod + @property + def params(cls): + params = [ + ("model", "str"), + ("messages", "list[dict[str, str]]"), + ("stream", "bool") + ] + param = ", ".join([": ".join(p) for p in params]) + return f"g4f.provider.{cls.__name__} supports: ({param})" \ No newline at end of file diff --git a/g4f/Provider/__init__.py b/g4f/Provider/__init__.py index 81d1ad64..432ae672 100644 --- a/g4f/Provider/__init__.py +++ b/g4f/Provider/__init__.py @@ -25,6 +25,7 @@ from .You import You from .Yqcloud import Yqcloud from .Equing import Equing from .FastGpt import FastGpt +from .Wuguokai import Wuguokai __all__ = [ "BaseProvider", @@ -53,5 +54,6 @@ __all__ = [ "You", "Yqcloud", "Equing", - "FastGpt" + "FastGpt", + "Wuguokai" ] -- cgit v1.2.3 From ce45d36936b4d33ebc41c6687095ca511a175a35 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Mon, 21 Aug 2023 22:39:57 +0200 Subject: Fix bing provider --- g4f/Provider/Bing.py | 464 ++++++++++++++++++++++----------------------------- 1 file changed, 203 insertions(+), 261 deletions(-) diff --git a/g4f/Provider/Bing.py b/g4f/Provider/Bing.py index 48b5477d..364e9c1d 100644 --- a/g4f/Provider/Bing.py +++ b/g4f/Provider/Bing.py @@ -2,17 +2,15 @@ import asyncio import json import os import random -import ssl -import uuid import aiohttp -import certifi -import requests +import asyncio +import browser_cookie3 +from aiohttp import ClientSession -from ..typing import Any, AsyncGenerator, CreateResult, Tuple, Union +from ..typing import Any, AsyncGenerator, CreateResult, Union from .base_provider import BaseProvider - class Bing(BaseProvider): url = "https://bing.com/chat" supports_gpt_4 = True @@ -22,20 +20,27 @@ class Bing(BaseProvider): model: str, messages: list[dict[str, str]], stream: bool, - **kwargs: Any, + **kwargs: Any ) -> CreateResult: - if len(messages) < 2: - prompt = messages[0]["content"] - context = False + yield from run(create(messages, **kwargs)) + +def create( + messages: list[dict[str, str]], + cookies: dict = {} + ): + if len(messages) < 2: + prompt = messages[0]["content"] + context = None - else: - prompt = messages[-1]["content"] - context = convert(messages[:-1]) + else: + prompt = messages[-1]["content"] + context = convert(messages[:-1]) - response = run(stream_generate(prompt, jailbreak, context)) - for token in response: - yield token + if not cookies: + for cookie in browser_cookie3.load(domain_name='.bing.com'): + cookies[cookie.name] = cookie.value + return stream_generate(prompt, context, cookies) def convert(messages: list[dict[str, str]]): context = "" @@ -45,250 +50,43 @@ def convert(messages: list[dict[str, str]]): return context - -jailbreak = { - "optionsSets": [ - "saharasugg", - "enablenewsfc", - "clgalileo", - "gencontentv3", - "nlu_direct_response_filter", - "deepleo", - "disable_emoji_spoken_text", - "responsible_ai_policy_235", - "enablemm", - "h3precise" - # "harmonyv3", - "dtappid", - "cricinfo", - "cricinfov2", - "dv3sugg", - "nojbfedge", - ] -} - - -ssl_context = ssl.create_default_context() -ssl_context.load_verify_locations(certifi.where()) - - -def _format(msg: dict[str, Any]) -> str: - return json.dumps(msg, ensure_ascii=False) + Defaults.delimiter - - -async def stream_generate( - prompt: str, - mode: dict[str, list[str]] = jailbreak, - context: Union[bool, str] = False, -): - timeout = aiohttp.ClientTimeout(total=900) - session = aiohttp.ClientSession(timeout=timeout) - - conversationId, clientId, conversationSignature = await create_conversation() - - wss = await session.ws_connect( - "wss://sydney.bing.com/sydney/ChatHub", - ssl=ssl_context, - autoping=False, - headers={ - "accept": "application/json", - "accept-language": "en-US,en;q=0.9", - "content-type": "application/json", - "sec-ch-ua": '"Not_A Brand";v="99", "Microsoft Edge";v="110", "Chromium";v="110"', - "sec-ch-ua-arch": '"x86"', - "sec-ch-ua-bitness": '"64"', - "sec-ch-ua-full-version": '"109.0.1518.78"', - "sec-ch-ua-full-version-list": '"Chromium";v="110.0.5481.192", "Not A(Brand";v="24.0.0.0", "Microsoft Edge";v="110.0.1587.69"', - "sec-ch-ua-mobile": "?0", - "sec-ch-ua-model": "", - "sec-ch-ua-platform": '"Windows"', - "sec-ch-ua-platform-version": '"15.0.0"', - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "same-origin", - "x-ms-client-request-id": str(uuid.uuid4()), - "x-ms-useragent": "azsdk-js-api-client-factory/1.0.0-beta.1 core-rest-pipeline/1.10.0 OS/Win32", - "Referer": "https://www.bing.com/search?q=Bing+AI&showconv=1&FORM=hpcodx", - "Referrer-Policy": "origin-when-cross-origin", - "x-forwarded-for": Defaults.ip_address, - }, - ) - - await wss.send_str(_format({"protocol": "json", "version": 1})) - await wss.receive(timeout=900) - - argument: dict[str, Any] = { - **mode, +class Conversation(): + def __init__(self, conversationId: str, clientId: str, conversationSignature: str) -> None: + self.conversationId = conversationId + self.clientId = clientId + self.conversationSignature = conversationSignature + +async def create_conversation(session: ClientSession) -> Conversation: + url = 'https://www.bing.com/turing/conversation/create' + async with await session.get(url) as response: + response = await response.json() + conversationId = response.get('conversationId') + clientId = response.get('clientId') + conversationSignature = response.get('conversationSignature') + + if not conversationId or not clientId or not conversationSignature: + raise Exception('Failed to create conversation.') + + return Conversation(conversationId, clientId, conversationSignature) + +async def list_conversations(session: ClientSession) -> list: + url = "https://www.bing.com/turing/conversation/chats" + async with session.get(url) as response: + response = await response.json() + return response["chats"] + +async def delete_conversation(session: ClientSession, conversation: Conversation) -> list: + url = "https://sydney.bing.com/sydney/DeleteSingleConversation" + json = { + "conversationId": conversation.conversationId, + "conversationSignature": conversation.conversationSignature, + "participant": {"id": conversation.clientId}, "source": "cib", - "allowedMessageTypes": Defaults.allowedMessageTypes, - "sliceIds": Defaults.sliceIds, - "traceId": os.urandom(16).hex(), - "isStartOfSession": True, - "message": Defaults.location - | { - "author": "user", - "inputMethod": "Keyboard", - "text": prompt, - "messageType": "Chat", - }, - "conversationSignature": conversationSignature, - "participant": {"id": clientId}, - "conversationId": conversationId, + "optionsSets": ["autosave"] } - - if context: - argument["previousMessages"] = [ - { - "author": "user", - "description": context, - "contextType": "WebPage", - "messageType": "Context", - "messageId": "discover-web--page-ping-mriduna-----", - } - ] - - struct: dict[str, list[dict[str, Any]] | str | int] = { - "arguments": [argument], - "invocationId": "0", - "target": "chat", - "type": 4, - } - - await wss.send_str(_format(struct)) - - final = False - draw = False - resp_txt = "" - result_text = "" - resp_txt_no_link = "" - cache_text = "" - - while not final: - msg = await wss.receive(timeout=900) - objects = msg.data.split(Defaults.delimiter) # type: ignore - - for obj in objects: # type: ignore - if obj is None or not obj: - continue - - response = json.loads(obj) # type: ignore - if response.get("type") == 1 and response["arguments"][0].get( - "messages", - ): - if not draw: - if ( - response["arguments"][0]["messages"][0]["contentOrigin"] - != "Apology" - ) and not draw: - resp_txt = result_text + response["arguments"][0]["messages"][ - 0 - ]["adaptiveCards"][0]["body"][0].get("text", "") - resp_txt_no_link = result_text + response["arguments"][0][ - "messages" - ][0].get("text", "") - - if response["arguments"][0]["messages"][0].get( - "messageType", - ): - resp_txt = ( - resp_txt - + response["arguments"][0]["messages"][0][ - "adaptiveCards" - ][0]["body"][0]["inlines"][0].get("text") - + "\n" - ) - result_text = ( - result_text - + response["arguments"][0]["messages"][0][ - "adaptiveCards" - ][0]["body"][0]["inlines"][0].get("text") - + "\n" - ) - - if cache_text.endswith(" "): - final = True - if wss and not wss.closed: - await wss.close() - if session and not session.closed: - await session.close() - - yield (resp_txt.replace(cache_text, "")) - cache_text = resp_txt - - elif response.get("type") == 2: - if response["item"]["result"].get("error"): - if wss and not wss.closed: - await wss.close() - if session and not session.closed: - await session.close() - - raise Exception( - f"{response['item']['result']['value']}: {response['item']['result']['message']}" - ) - - if draw: - cache = response["item"]["messages"][1]["adaptiveCards"][0]["body"][ - 0 - ]["text"] - response["item"]["messages"][1]["adaptiveCards"][0]["body"][0][ - "text" - ] = (cache + resp_txt) - - if ( - response["item"]["messages"][-1]["contentOrigin"] == "Apology" - and resp_txt - ): - response["item"]["messages"][-1]["text"] = resp_txt_no_link - response["item"]["messages"][-1]["adaptiveCards"][0]["body"][0][ - "text" - ] = resp_txt - - # print('Preserved the message from being deleted', file=sys.stderr) - - final = True - if wss and not wss.closed: - await wss.close() - if session and not session.closed: - await session.close() - - -async def create_conversation() -> Tuple[str, str, str]: - create = requests.get( - "https://www.bing.com/turing/conversation/create", - headers={ - "authority": "edgeservices.bing.com", - "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", - "accept-language": "en-US,en;q=0.9", - "cache-control": "max-age=0", - "sec-ch-ua": '"Chromium";v="110", "Not A(Brand";v="24", "Microsoft Edge";v="110"', - "sec-ch-ua-arch": '"x86"', - "sec-ch-ua-bitness": '"64"', - "sec-ch-ua-full-version": '"110.0.1587.69"', - "sec-ch-ua-full-version-list": '"Chromium";v="110.0.5481.192", "Not A(Brand";v="24.0.0.0", "Microsoft Edge";v="110.0.1587.69"', - "sec-ch-ua-mobile": "?0", - "sec-ch-ua-model": '""', - "sec-ch-ua-platform": '"Windows"', - "sec-ch-ua-platform-version": '"15.0.0"', - "sec-fetch-dest": "document", - "sec-fetch-mode": "navigate", - "sec-fetch-site": "none", - "sec-fetch-user": "?1", - "upgrade-insecure-requests": "1", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.69", - "x-edge-shopping-flag": "1", - "x-forwarded-for": Defaults.ip_address, - }, - ) - - conversationId = create.json().get("conversationId") - clientId = create.json().get("clientId") - conversationSignature = create.json().get("conversationSignature") - - if not conversationId or not clientId or not conversationSignature: - raise Exception("Failed to create conversation.") - - return conversationId, clientId, conversationSignature - + async with session.post(url, json=json) as response: + response = await response.json() + return response["result"]["value"] == "Success" class Defaults: delimiter = "\x1e" @@ -309,9 +107,6 @@ class Defaults: ] sliceIds = [ - # "222dtappid", - # "225cricinfo", - # "224locals0" "winmuid3tf", "osbsdusgreccf", "ttstmout", @@ -349,6 +144,153 @@ class Defaults: ], } + headers = { + 'accept': '*/*', + 'accept-language': 'en-US,en;q=0.9', + 'cache-control': 'max-age=0', + 'sec-ch-ua': '"Chromium";v="110", "Not A(Brand";v="24", "Microsoft Edge";v="110"', + 'sec-ch-ua-arch': '"x86"', + 'sec-ch-ua-bitness': '"64"', + 'sec-ch-ua-full-version': '"110.0.1587.69"', + 'sec-ch-ua-full-version-list': '"Chromium";v="110.0.5481.192", "Not A(Brand";v="24.0.0.0", "Microsoft Edge";v="110.0.1587.69"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-model': '""', + 'sec-ch-ua-platform': '"Windows"', + 'sec-ch-ua-platform-version': '"15.0.0"', + 'sec-fetch-dest': 'document', + 'sec-fetch-mode': 'navigate', + 'sec-fetch-site': 'none', + 'sec-fetch-user': '?1', + 'upgrade-insecure-requests': '1', + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.69', + 'x-edge-shopping-flag': '1', + 'x-forwarded-for': ip_address, + } + + optionsSets = { + "optionsSets": [ + 'saharasugg', + 'enablenewsfc', + 'clgalileo', + 'gencontentv3', + "nlu_direct_response_filter", + "deepleo", + "disable_emoji_spoken_text", + "responsible_ai_policy_235", + "enablemm", + "h3precise" + "dtappid", + "cricinfo", + "cricinfov2", + "dv3sugg", + "nojbfedge" + ] + } + +def format_message(msg: dict) -> str: + return json.dumps(msg, ensure_ascii=False) + Defaults.delimiter + +def create_message(conversation: Conversation, prompt: str, context: str=None) -> str: + struct = { + 'arguments': [ + { + **Defaults.optionsSets, + 'source': 'cib', + 'allowedMessageTypes': Defaults.allowedMessageTypes, + 'sliceIds': Defaults.sliceIds, + 'traceId': os.urandom(16).hex(), + 'isStartOfSession': True, + 'message': Defaults.location | { + 'author': 'user', + 'inputMethod': 'Keyboard', + 'text': prompt, + 'messageType': 'Chat' + }, + 'conversationSignature': conversation.conversationSignature, + 'participant': { + 'id': conversation.clientId + }, + 'conversationId': conversation.conversationId + } + ], + 'invocationId': '0', + 'target': 'chat', + 'type': 4 + } + + if context: + struct['arguments'][0]['previousMessages'] = [{ + "author": "user", + "description": context, + "contextType": "WebPage", + "messageType": "Context", + "messageId": "discover-web--page-ping-mriduna-----" + }] + return format_message(struct) + +async def stream_generate( + prompt: str, + context: str=None, + cookies: dict=None + ): + async with ClientSession( + timeout=aiohttp.ClientTimeout(total=900), + cookies=cookies, + headers=Defaults.headers, + ) as session: + conversation = await create_conversation(session) + try: + async with session.ws_connect( + 'wss://sydney.bing.com/sydney/ChatHub', + autoping=False, + ) as wss: + + await wss.send_str(format_message({'protocol': 'json', 'version': 1})) + msg = await wss.receive(timeout=900) + + await wss.send_str(create_message(conversation, prompt, context)) + + response_txt = '' + result_text = '' + returned_text = '' + final = False + + while not final: + msg = await wss.receive(timeout=900) + objects = msg.data.split(Defaults.delimiter) + for obj in objects: + if obj is None or not obj: + continue + + response = json.loads(obj) + if response.get('type') == 1 and response['arguments'][0].get('messages'): + message = response['arguments'][0]['messages'][0] + if (message['contentOrigin'] != 'Apology'): + response_txt = result_text + \ + message['adaptiveCards'][0]['body'][0].get('text', '') + + if message.get('messageType'): + inline_txt = message['adaptiveCards'][0]['body'][0]['inlines'][0].get('text') + response_txt += inline_txt + '\n' + result_text += inline_txt + '\n' + + if returned_text.endswith(' '): + final = True + break + + if response_txt.startswith(returned_text): + new = response_txt[len(returned_text):] + if new != "\n": + yield new + returned_text = response_txt + elif response.get('type') == 2: + result = response['item']['result'] + if result.get('error'): + raise Exception(f"{result['value']}: {result['message']}") + final = True + break + finally: + await delete_conversation(session, conversation) def run(generator: AsyncGenerator[Union[Any, str], Any]): loop = asyncio.get_event_loop() -- cgit v1.2.3 From 98d3304108de3e55c18f2af8a66a501541ec658b Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Tue, 22 Aug 2023 23:27:34 +0200 Subject: Improve providers with tests --- g4f/Provider/DfeHub.py | 1 + g4f/Provider/FastGpt.py | 2 +- g4f/Provider/H2o.py | 8 +++++--- g4f/Provider/V50.py | 5 +++-- g4f/Provider/Wewordle.py | 7 +------ g4f/Provider/You.py | 15 +++++++-------- testing/test_providers.py | 42 ++++++++++++++++++++++-------------------- 7 files changed, 40 insertions(+), 40 deletions(-) diff --git a/g4f/Provider/DfeHub.py b/g4f/Provider/DfeHub.py index 4093d0e4..5a7b22e1 100644 --- a/g4f/Provider/DfeHub.py +++ b/g4f/Provider/DfeHub.py @@ -50,6 +50,7 @@ class DfeHub(BaseProvider): "https://chat.dfehub.com/api/openai/v1/chat/completions", headers=headers, json=json_data, + timeout=3 ) for chunk in response.iter_lines(): diff --git a/g4f/Provider/FastGpt.py b/g4f/Provider/FastGpt.py index 950abab1..3c5a4420 100644 --- a/g4f/Provider/FastGpt.py +++ b/g4f/Provider/FastGpt.py @@ -6,7 +6,7 @@ from ..typing import Any, CreateResult class FastGpt(ABC): url: str = 'https://chat9.fastgpt.me/' - working = True + working = False needs_auth = False supports_stream = True supports_gpt_35_turbo = True diff --git a/g4f/Provider/H2o.py b/g4f/Provider/H2o.py index f9b799bb..305a0bbf 100644 --- a/g4f/Provider/H2o.py +++ b/g4f/Provider/H2o.py @@ -11,6 +11,7 @@ class H2o(BaseProvider): url = "https://gpt-gm.h2o.ai" working = True supports_stream = True + model = "h2oai/h2ogpt-gm-oasst1-en-2048-falcon-40b-v1" @staticmethod def create_completion( @@ -47,8 +48,9 @@ class H2o(BaseProvider): "https://gpt-gm.h2o.ai/conversation", headers=headers, json=data, - ) - conversation_id = response.json()["conversationId"] + ).json() + if "conversationId" not in response: + return data = { "inputs": conversation, @@ -71,7 +73,7 @@ class H2o(BaseProvider): } response = session.post( - f"https://gpt-gm.h2o.ai/conversation/{conversation_id}", + f"https://gpt-gm.h2o.ai/conversation/{response['conversationId']}", headers=headers, json=data, ) diff --git a/g4f/Provider/V50.py b/g4f/Provider/V50.py index 125dd7c5..765f73bd 100644 --- a/g4f/Provider/V50.py +++ b/g4f/Provider/V50.py @@ -8,7 +8,7 @@ class V50(BaseProvider): supports_gpt_35_turbo = True supports_stream = False needs_auth = False - working = True + working = False @staticmethod def create_completion( @@ -46,7 +46,8 @@ class V50(BaseProvider): } response = requests.post("https://p5.v50.ltd/api/chat-process", json=payload, headers=headers, proxies=kwargs['proxy'] if 'proxy' in kwargs else {}) - yield response.text + if "https://fk1.v50.ltd" not in response.text: + yield response.text @classmethod @property diff --git a/g4f/Provider/Wewordle.py b/g4f/Provider/Wewordle.py index f7f47ee0..cef209c9 100644 --- a/g4f/Provider/Wewordle.py +++ b/g4f/Provider/Wewordle.py @@ -21,11 +21,6 @@ class Wewordle(BaseProvider): stream: bool, **kwargs: Any, ) -> CreateResult: - base = "" - - for message in messages: - base += "%s: %s\n" % (message["role"], message["content"]) - base += "assistant:" # randomize user id and app id _user_id = "".join( random.choices(f"{string.ascii_lowercase}{string.digits}", k=16) @@ -45,7 +40,7 @@ class Wewordle(BaseProvider): } data: dict[str, Any] = { "user": _user_id, - "messages": [{"role": "user", "content": base}], + "messages": messages, "subscriber": { "originalPurchaseDate": None, "originalApplicationVersion": None, diff --git a/g4f/Provider/You.py b/g4f/Provider/You.py index 0d8114a8..cbd741ba 100644 --- a/g4f/Provider/You.py +++ b/g4f/Provider/You.py @@ -1,5 +1,6 @@ import re import urllib.parse +import json from curl_cffi import requests @@ -28,7 +29,11 @@ class You(BaseProvider): impersonate="chrome107", ) response.raise_for_status() - yield _parse_output(response.text) + start = 'data: {"youChatToken": ' + for line in response.content.splitlines(): + line = line.decode('utf-8') + if line.startswith(start): + yield json.loads(line[len(start): -1]) def _create_url_param(messages: list[dict[str, str]]): @@ -50,10 +55,4 @@ def _create_header(): return { "accept": "text/event-stream", "referer": "https://you.com/search?fromSearchBar=true&tbm=youchat", - } - - -def _parse_output(output: str) -> str: - regex = r"^data:\s{\"youChatToken\": \"(.*)\"}$" - tokens = [token for token in re.findall(regex, output, re.MULTILINE)] - return "".join(tokens) + } \ No newline at end of file diff --git a/testing/test_providers.py b/testing/test_providers.py index a5c6f87b..fee79e20 100644 --- a/testing/test_providers.py +++ b/testing/test_providers.py @@ -3,50 +3,51 @@ from pathlib import Path sys.path.append(str(Path(__file__).parent.parent)) -from g4f import BaseProvider, models, provider +from g4f import BaseProvider, models, Provider +logging = False def main(): providers = get_providers() - results: list[list[str | bool]] = [] + failed_providers = [] for _provider in providers: - print("start", _provider.__name__) - actual_working = judge(_provider) - expected_working = _provider.working - match = actual_working == expected_working + if _provider.needs_auth: + continue + print("Provider:", _provider.__name__) + result = judge(_provider) + print("Result:", result) + if _provider.working and not result: + failed_providers.append([_provider, result]) - results.append([_provider.__name__, expected_working, actual_working, match]) - - print("failed provider list") - for result in results: - if not result[3]: - print(result) + print("Failed providers:") + for _provider, result in failed_providers: + print(f"{_provider.__name__}: {result}") def get_providers() -> list[type[BaseProvider]]: - provider_names = dir(provider) + provider_names = dir(Provider) ignore_names = [ "base_provider", - "BaseProvider", + "BaseProvider" ] provider_names = [ provider_name for provider_name in provider_names if not provider_name.startswith("__") and provider_name not in ignore_names ] - return [getattr(provider, provider_name) for provider_name in provider_names] + return [getattr(Provider, provider_name) for provider_name in provider_names] def create_response(_provider: type[BaseProvider]) -> str: model = ( models.gpt_35_turbo.name - if _provider is not provider.H2o - else models.falcon_7b.name + if _provider.supports_gpt_35_turbo + else _provider.model ) response = _provider.create_completion( model=model, - messages=[{"role": "user", "content": "Hello world!, plz yourself"}], + messages=[{"role": "user", "content": "Hello world!"}], stream=False, ) return "".join(response) @@ -59,9 +60,10 @@ def judge(_provider: type[BaseProvider]) -> bool: try: response = create_response(_provider) assert type(response) is str - return len(response) > 1 + return response except Exception as e: - print(e) + if logging: + print(e) return False -- cgit v1.2.3 From d1b6921b5fa3d9dbd7f1cce6e4f396744a7a2274 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Wed, 23 Aug 2023 02:16:35 +0200 Subject: Add create_async method --- g4f/Provider/Bing.py | 58 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/g4f/Provider/Bing.py b/g4f/Provider/Bing.py index 364e9c1d..b9b9e9a4 100644 --- a/g4f/Provider/Bing.py +++ b/g4f/Provider/Bing.py @@ -13,34 +13,54 @@ from .base_provider import BaseProvider class Bing(BaseProvider): url = "https://bing.com/chat" + working = True supports_gpt_4 = True - @staticmethod + @classmethod def create_completion( + cls, model: str, messages: list[dict[str, str]], stream: bool, **kwargs: Any ) -> CreateResult: - yield from run(create(messages, **kwargs)) - -def create( + if stream: + yield from run(cls.create_async_generator(model, messages, **kwargs)) + else: + yield asyncio.run(cls.create_async(model, messages, **kwargs)) + + @classmethod + async def create_async( + cls, + model: str, messages: list[dict[str, str]], - cookies: dict = {} - ): - if len(messages) < 2: - prompt = messages[0]["content"] - context = None - - else: - prompt = messages[-1]["content"] - context = convert(messages[:-1]) - - if not cookies: - for cookie in browser_cookie3.load(domain_name='.bing.com'): - cookies[cookie.name] = cookie.value - - return stream_generate(prompt, context, cookies) + **kwargs: Any, + ) -> str: + result = [] + async for chunk in cls.create_async_generator(model, messages, **kwargs): + result.append(chunk) + if result: + return "".join(result) + + @staticmethod + def create_async_generator( + model: str, + messages: list[dict[str, str]], + cookies: dict = {} + ) -> AsyncGenerator: + if len(messages) < 2: + prompt = messages[0]["content"] + context = None + + else: + prompt = messages[-1]["content"] + context = convert(messages[:-1]) + + if not cookies: + for cookie in browser_cookie3.load(domain_name='.bing.com'): + cookies[cookie.name] = cookie.value + + return stream_generate(prompt, context, cookies) def convert(messages: list[dict[str, str]]): context = "" -- cgit v1.2.3 From 7222d9b7cea4db173258c1189f5069b544606eeb Mon Sep 17 00:00:00 2001 From: zengrr <47846202+zeng-rr@users.noreply.github.com> Date: Wed, 23 Aug 2023 15:26:00 +0800 Subject: "You" unicode decode and fix prompt just is last message --- g4f/Provider/You.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/g4f/Provider/You.py b/g4f/Provider/You.py index 0d8114a8..a8de7dec 100644 --- a/g4f/Provider/You.py +++ b/g4f/Provider/You.py @@ -19,7 +19,7 @@ class You(BaseProvider): stream: bool, **kwargs: Any, ) -> CreateResult: - url_param = _create_url_param(messages) + url_param = _create_url_param(messages, kwargs.get("history", [])) headers = _create_header() url = f"https://you.com/api/streamingSearch?{url_param}" response = requests.get( @@ -28,12 +28,15 @@ class You(BaseProvider): impersonate="chrome107", ) response.raise_for_status() - yield _parse_output(response.text) + yield _parse_output(response.text).encode().decode("unicode_escape") -def _create_url_param(messages: list[dict[str, str]]): - prompt = messages.pop()["content"] - chat = _convert_chat(messages) +def _create_url_param(messages: list[dict[str, str]], history: list[dict[str, str]]): + prompt = "" + for message in messages: + prompt += "%s: %s\n" % (message["role"], message["content"]) + prompt += "assistant:" + chat = _convert_chat(history) param = {"q": prompt, "domain": "youchat", "chat": chat} return urllib.parse.urlencode(param) -- cgit v1.2.3 From 6a4463889eab6cfa4d73efd2aff7c2904640444c Mon Sep 17 00:00:00 2001 From: zengrr <47846202+zeng-rr@users.noreply.github.com> Date: Wed, 23 Aug 2023 15:34:38 +0800 Subject: fix Yqcloud's prompter using only the last message --- g4f/Provider/Yqcloud.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/g4f/Provider/Yqcloud.py b/g4f/Provider/Yqcloud.py index a3147c2d..82ece2d5 100644 --- a/g4f/Provider/Yqcloud.py +++ b/g4f/Provider/Yqcloud.py @@ -35,7 +35,10 @@ def _create_header(): def _create_payload(messages: list[dict[str, str]]): - prompt = messages[-1]["content"] + prompt = "" + for message in messages: + prompt += "%s: %s\n" % (message["role"], message["content"]) + prompt += "assistant:" return { "prompt": prompt, "network": True, -- cgit v1.2.3 From 1ed448e584092e151212b1d511fd2cbec133064b Mon Sep 17 00:00:00 2001 From: zengrr <47846202+zeng-rr@users.noreply.github.com> Date: Wed, 23 Aug 2023 19:36:30 +0800 Subject: Ails throw the contents of an error response --- g4f/Provider/Ails.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/g4f/Provider/Ails.py b/g4f/Provider/Ails.py index 52b3745d..806544b4 100644 --- a/g4f/Provider/Ails.py +++ b/g4f/Provider/Ails.py @@ -72,6 +72,8 @@ class Ails(BaseProvider): if b"content" in token: completion_chunk = json.loads(token.decode().replace("data: ", "")) token = completion_chunk["choices"][0]["delta"].get("content") + if "ai.ls".lower() in token.lower(): + raise Exception("Response Error: " + token) if token != None: yield token -- cgit v1.2.3 From e56f9b7c0dee64eec3843da1fd68f2d0c90b875d Mon Sep 17 00:00:00 2001 From: Bagus Indrayana Date: Thu, 24 Aug 2023 18:13:20 +0800 Subject: remove whitspace from data: and raise exception --- g4f/Provider/EasyChat.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/g4f/Provider/EasyChat.py b/g4f/Provider/EasyChat.py index 2a61346c..3c6562f0 100644 --- a/g4f/Provider/EasyChat.py +++ b/g4f/Provider/EasyChat.py @@ -75,16 +75,18 @@ class EasyChat(BaseProvider): if "choices" in json_data: yield json_data["choices"][0]["message"]["content"] else: - yield Exception("No response from server") + raise Exception("No response from server") else: for chunk in response.iter_lines(): if b"content" in chunk: - splitData = chunk.decode().split("data: ") + splitData = chunk.decode().split("data:") if len(splitData) > 1: yield json.loads(splitData[1])["choices"][0]["delta"]["content"] + else: + continue else: - yield Exception(f"Error {response.status_code} from server") + raise Exception(f"Error {response.status_code} from server : {response.reason}") @classmethod -- cgit v1.2.3 From 69ca98ac85743edd76ac6ce49feb233cd5365099 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Thu, 24 Aug 2023 21:32:22 +0200 Subject: Improve provider list --- README.md | 51 +++++++++++++++++++++++++---------------------- g4f/Provider/AItianhu.py | 2 +- g4f/Provider/Acytoo.py | 8 ++++---- g4f/Provider/AiService.py | 2 +- g4f/Provider/DfeHub.py | 2 +- g4f/Provider/Wewordle.py | 8 ++++---- testing/test_providers.py | 33 ++++++++++++++++++++---------- tool/readme_table.py | 47 ++++++++++++++++++++++++------------------- 8 files changed, 88 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index 39b368cc..22db26cc 100644 --- a/README.md +++ b/README.md @@ -185,30 +185,33 @@ if __name__ == "__main__": | Website| Provider| gpt-3.5 | gpt-4 | Streaming | Status | Auth | | ------ | ------- | ------- | ----- | --------- | ------ | ---- | -| [www.aitianhu.com](https://www.aitianhu.com/api/chat-process) | g4f.Provider.AItianhu | ✔️ | ❌ | ❌ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | -| [chat.acytoo.com](https://chat.acytoo.com/api/completions) | g4f.Provider.Acytoo | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [aiservice.vercel.app](https://aiservice.vercel.app/api/chat/answer) | g4f.Provider.AiService | ✔️ | ❌ | ❌ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | -| [chat-gpt.org](https://chat-gpt.org/chat) | g4f.Provider.Aichat | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [ai.ls](https://ai.ls) | g4f.Provider.Ails | ✔️ | ❌ | ✔️ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [bard.google.com](https://bard.google.com) | g4f.Provider.Bard | ❌ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ✔️ | -| [bing.com](https://bing.com/chat) | g4f.Provider.Bing | ❌ | ✔️ | ❌ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | -| [chatgpt.ai](https://chatgpt.ai/gpt-4/) | g4f.Provider.ChatgptAi | ❌ | ✔️ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [chatgptlogin.ac](https://chatgptlogin.ac) | g4f.Provider.ChatgptLogin | ✔️ | ❌ | ❌ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | -| [deepai.org](https://deepai.org) | g4f.Provider.DeepAi | ✔️ | ❌ | ✔️ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [chat.dfehub.com](https://chat.dfehub.com/api/chat) | g4f.Provider.DfeHub | ✔️ | ❌ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | -| [free.easychat.work](https://free.easychat.work) | g4f.Provider.EasyChat | ✔️ | ❌ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | -| [forefront.com](https://forefront.com) | g4f.Provider.Forefront | ✔️ | ❌ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | -| [chat.getgpt.world](https://chat.getgpt.world/) | g4f.Provider.GetGpt | ✔️ | ❌ | ✔️ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [gpt-gm.h2o.ai](https://gpt-gm.h2o.ai) | g4f.Provider.H2o | ❌ | ❌ | ✔️ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [liaobots.com](https://liaobots.com) | g4f.Provider.Liaobots | ✔️ | ✔️ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ✔️ | -| [supertest.lockchat.app](http://supertest.lockchat.app) | g4f.Provider.Lockchat | ✔️ | ✔️ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | -| [opchatgpts.net](https://opchatgpts.net) | g4f.Provider.Opchatgpts | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [backend.raycast.com](https://backend.raycast.com/api/v1/ai/chat_completions) | g4f.Provider.Raycast | ✔️ | ✔️ | ✔️ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ✔️ | -| [theb.ai](https://theb.ai) | g4f.Provider.Theb | ✔️ | ❌ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | -| [play.vercel.ai](https://play.vercel.ai) | g4f.Provider.Vercel | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [wewordle.org](https://wewordle.org/gptapi/v1/android/turbo) | g4f.Provider.Wewordle | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [you.com](https://you.com) | g4f.Provider.You | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | -| [chat9.yqcloud.top](https://chat9.yqcloud.top/) | g4f.Provider.Yqcloud | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [chat.acytoo.com](https://chat.acytoo.com/) | g4f.provider.Acytoo | ✔️ | ❌ | ❌ | ![Unknown](https://img.shields.io/badge/Unknown-grey) | ❌ | +| [chat-gpt.org](https://chat-gpt.org/chat) | g4f.provider.Aichat | ✔️ | ❌ | ❌ | ![Unknown](https://img.shields.io/badge/Unknown-grey) | ❌ | +| [ai.ls](https://ai.ls) | g4f.provider.Ails | ✔️ | ❌ | ✔️ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [bard.google.com](https://bard.google.com) | g4f.provider.Bard | ❌ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ✔️ | +| [chatgpt.ai](https://chatgpt.ai/gpt-4/) | g4f.provider.ChatgptAi | ❌ | ✔️ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [opchatgpts.net](https://opchatgpts.net) | g4f.provider.ChatgptLogin | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [deepai.org](https://deepai.org) | g4f.provider.DeepAi | ✔️ | ❌ | ✔️ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [free.easychat.work](https://free.easychat.work) | g4f.provider.EasyChat | ✔️ | ❌ | ✔️ | ![Unknown](https://img.shields.io/badge/Unknown-grey) | ❌ | +| [next.eqing.tech](https://next.eqing.tech/) | g4f.provider.Equing | ✔️ | ❌ | ✔️ | ![Unknown](https://img.shields.io/badge/Unknown-grey) | ❌ | +| [chat.getgpt.world](https://chat.getgpt.world/) | g4f.provider.GetGpt | ✔️ | ❌ | ✔️ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [gpt-gm.h2o.ai](https://gpt-gm.h2o.ai) | g4f.provider.H2o | ❌ | ❌ | ✔️ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [opchatgpts.net](https://opchatgpts.net) | g4f.provider.Opchatgpts | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [raycast.com](https://raycast.com) | g4f.provider.Raycast | ✔️ | ✔️ | ✔️ | ![Unknown](https://img.shields.io/badge/Unknown-grey) | ✔️ | +| [theb.ai](https://theb.ai) | g4f.provider.Theb | ✔️ | ❌ | ✔️ | ![Unknown](https://img.shields.io/badge/Unknown-grey) | ✔️ | +| [play.vercel.ai](https://play.vercel.ai) | g4f.provider.Vercel | ✔️ | ❌ | ❌ | ![Unknown](https://img.shields.io/badge/Unknown-grey) | ❌ | +| [wewordle.org](https://wewordle.org/) | g4f.provider.Wewordle | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [you.com](https://you.com) | g4f.provider.You | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [chat9.yqcloud.top](https://chat9.yqcloud.top/) | g4f.provider.Yqcloud | ✔️ | ❌ | ❌ | ![Active](https://img.shields.io/badge/Active-brightgreen) | ❌ | +| [www.aitianhu.com](https://www.aitianhu.com/) | g4f.provider.AItianhu | ✔️ | ❌ | ❌ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | +| [aiservice.vercel.app](https://aiservice.vercel.app/) | g4f.provider.AiService | ✔️ | ❌ | ❌ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | +| [bing.com](https://bing.com/chat) | g4f.provider.Bing | ❌ | ✔️ | ❌ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | +| [chat.dfehub.com](https://chat.dfehub.com/) | g4f.provider.DfeHub | ✔️ | ❌ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | +| [chat9.fastgpt.me](https://chat9.fastgpt.me/) | g4f.provider.FastGpt | ✔️ | ❌ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | +| [forefront.com](https://forefront.com) | g4f.provider.Forefront | ✔️ | ❌ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | +| [liaobots.com](https://liaobots.com) | g4f.provider.Liaobots | ✔️ | ✔️ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ✔️ | +| [supertest.lockchat.app](http://supertest.lockchat.app) | g4f.provider.Lockchat | ✔️ | ✔️ | ✔️ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | +| [p5.v50.ltd](https://p5.v50.ltd) | g4f.provider.V50 | ✔️ | ❌ | ❌ | ![Inactive](https://img.shields.io/badge/Inactive-red) | ❌ | ### Other Models diff --git a/g4f/Provider/AItianhu.py b/g4f/Provider/AItianhu.py index e8e5714a..9f5440bc 100644 --- a/g4f/Provider/AItianhu.py +++ b/g4f/Provider/AItianhu.py @@ -7,7 +7,7 @@ from .base_provider import BaseProvider class AItianhu(BaseProvider): - url = "https://www.aitianhu.com/api/chat-process" + url = "https://www.aitianhu.com/" working = False supports_gpt_35_turbo = True diff --git a/g4f/Provider/Acytoo.py b/g4f/Provider/Acytoo.py index 2edd9efd..975e914b 100644 --- a/g4f/Provider/Acytoo.py +++ b/g4f/Provider/Acytoo.py @@ -7,12 +7,13 @@ from .base_provider import BaseProvider class Acytoo(BaseProvider): - url = "https://chat.acytoo.com/api/completions" + url = "https://chat.acytoo.com/" working = True supports_gpt_35_turbo = True - @staticmethod + @classmethod def create_completion( + cls, model: str, messages: list[dict[str, str]], stream: bool, @@ -21,8 +22,7 @@ class Acytoo(BaseProvider): headers = _create_header() payload = _create_payload(messages, kwargs.get('temperature', 0.5)) - url = "https://chat.acytoo.com/api/completions" - response = requests.post(url=url, headers=headers, json=payload) + response = requests.post("{cls.url}api/completions", headers=headers, json=payload) response.raise_for_status() response.encoding = "utf-8" yield response.text diff --git a/g4f/Provider/AiService.py b/g4f/Provider/AiService.py index 2c0d5de2..3453bfd9 100644 --- a/g4f/Provider/AiService.py +++ b/g4f/Provider/AiService.py @@ -5,7 +5,7 @@ from .base_provider import BaseProvider class AiService(BaseProvider): - url = "https://aiservice.vercel.app/api/chat/answer" + url = "https://aiservice.vercel.app/" working = False supports_gpt_35_turbo = True diff --git a/g4f/Provider/DfeHub.py b/g4f/Provider/DfeHub.py index 5a7b22e1..6f96ec7a 100644 --- a/g4f/Provider/DfeHub.py +++ b/g4f/Provider/DfeHub.py @@ -9,7 +9,7 @@ from .base_provider import BaseProvider class DfeHub(BaseProvider): - url = "https://chat.dfehub.com/api/chat" + url = "https://chat.dfehub.com/" supports_stream = True supports_gpt_35_turbo = True diff --git a/g4f/Provider/Wewordle.py b/g4f/Provider/Wewordle.py index cef209c9..8e106716 100644 --- a/g4f/Provider/Wewordle.py +++ b/g4f/Provider/Wewordle.py @@ -10,12 +10,13 @@ from .base_provider import BaseProvider class Wewordle(BaseProvider): - url = "https://wewordle.org/gptapi/v1/android/turbo" + url = "https://wewordle.org/" working = True supports_gpt_35_turbo = True - @staticmethod + @classmethod def create_completion( + cls, model: str, messages: list[dict[str, str]], stream: bool, @@ -62,8 +63,7 @@ class Wewordle(BaseProvider): }, } - url = "https://wewordle.org/gptapi/v1/android/turbo" - response = requests.post(url, headers=headers, data=json.dumps(data)) + response = requests.post(f"{cls.url}gptapi/v1/android/turbo", headers=headers, data=json.dumps(data)) response.raise_for_status() _json = response.json() if "message" in _json: diff --git a/testing/test_providers.py b/testing/test_providers.py index fee79e20..6d3b62d8 100644 --- a/testing/test_providers.py +++ b/testing/test_providers.py @@ -1,5 +1,6 @@ import sys from pathlib import Path +from colorama import Fore sys.path.append(str(Path(__file__).parent.parent)) @@ -20,9 +21,14 @@ def main(): if _provider.working and not result: failed_providers.append([_provider, result]) - print("Failed providers:") - for _provider, result in failed_providers: - print(f"{_provider.__name__}: {result}") + print() + + if failed_providers: + print(f"{Fore.RED}Failed providers:\n") + for _provider, result in failed_providers: + print(f"{Fore.RED}{_provider.__name__}") + else: + print(f"{Fore.GREEN}All providers are working") def get_providers() -> list[type[BaseProvider]]: @@ -36,18 +42,21 @@ def get_providers() -> list[type[BaseProvider]]: for provider_name in provider_names if not provider_name.startswith("__") and provider_name not in ignore_names ] - return [getattr(Provider, provider_name) for provider_name in provider_names] + return [getattr(Provider, provider_name) for provider_name in sorted(provider_names)] def create_response(_provider: type[BaseProvider]) -> str: - model = ( - models.gpt_35_turbo.name - if _provider.supports_gpt_35_turbo - else _provider.model - ) + if _provider.supports_gpt_35_turbo: + model = models.gpt_35_turbo.name + elif _provider.supports_gpt_4: + model = models.gpt_4 + elif hasattr(_provider, "model"): + model = _provider.model + else: + model = None response = _provider.create_completion( model=model, - messages=[{"role": "user", "content": "Hello world!"}], + messages=[{"role": "user", "content": "Hello"}], stream=False, ) return "".join(response) @@ -57,9 +66,13 @@ def judge(_provider: type[BaseProvider]) -> bool: if _provider.needs_auth: return _provider.working + return test(_provider) + +def test(_provider: type[BaseProvider]) -> bool: try: response = create_response(_provider) assert type(response) is str + assert len(response) > 0 return response except Exception as e: if logging: diff --git a/tool/readme_table.py b/tool/readme_table.py index 10735ba0..b578b9ca 100644 --- a/tool/readme_table.py +++ b/tool/readme_table.py @@ -7,7 +7,7 @@ sys.path.append(str(Path(__file__).parent.parent)) from g4f import models, Provider from g4f.Provider.base_provider import BaseProvider - +from testing.test_providers import test def main(): print_providers() @@ -21,25 +21,30 @@ def print_providers(): "| ------ | ------- | ------- | ----- | --------- | ------ | ---- |", ] providers = get_providers() - for _provider in providers: - netloc = urlparse(_provider.url).netloc - website = f"[{netloc}]({_provider.url})" - - provider_name = f"g4f.provider.{_provider.__name__}" - - has_gpt_35 = "✔️" if _provider.supports_gpt_35_turbo else "❌" - has_gpt_4 = "✔️" if _provider.supports_gpt_4 else "❌" - stream = "✔️" if _provider.supports_stream else "❌" - status = ( - "![Active](https://img.shields.io/badge/Active-brightgreen)" - if _provider.working - else "![Inactive](https://img.shields.io/badge/Inactive-red)" - ) - auth = "✔️" if _provider.needs_auth else "❌" - - lines.append( - f"| {website} | {provider_name} | {has_gpt_35} | {has_gpt_4} | {stream} | {status} | {auth} |" - ) + for is_working in (True, False): + for _provider in providers: + if is_working != _provider.working: + continue + netloc = urlparse(_provider.url).netloc + website = f"[{netloc}]({_provider.url})" + + provider_name = f"g4f.provider.{_provider.__name__}" + + has_gpt_35 = "✔️" if _provider.supports_gpt_35_turbo else "❌" + has_gpt_4 = "✔️" if _provider.supports_gpt_4 else "❌" + stream = "✔️" if _provider.supports_stream else "❌" + if _provider.working: + if test(_provider): + status = '![Active](https://img.shields.io/badge/Active-brightgreen)' + else: + status = '![Unknown](https://img.shields.io/badge/Unknown-grey)' + else: + status = '![Inactive](https://img.shields.io/badge/Inactive-red)' + auth = "✔️" if _provider.needs_auth else "❌" + + lines.append( + f"| {website} | {provider_name} | {has_gpt_35} | {has_gpt_4} | {stream} | {status} | {auth} |" + ) print("\n".join(lines)) @@ -79,6 +84,8 @@ def print_models(): _models = get_models() for model in _models: + if model.best_provider.__name__ not in provider_urls: + continue split_name = re.split(r":|/", model.name) name = split_name[-1] -- cgit v1.2.3 From 1f56c792220427b86ec7780a7a298d14f205b466 Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Fri, 25 Aug 2023 00:32:13 +0200 Subject: Remove judge function --- testing/test_providers.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/testing/test_providers.py b/testing/test_providers.py index 6d3b62d8..c4fcbc0c 100644 --- a/testing/test_providers.py +++ b/testing/test_providers.py @@ -16,16 +16,16 @@ def main(): if _provider.needs_auth: continue print("Provider:", _provider.__name__) - result = judge(_provider) + result = test(_provider) print("Result:", result) if _provider.working and not result: - failed_providers.append([_provider, result]) + failed_providers.append(_provider) print() if failed_providers: print(f"{Fore.RED}Failed providers:\n") - for _provider, result in failed_providers: + for _provider in failed_providers: print(f"{Fore.RED}{_provider.__name__}") else: print(f"{Fore.GREEN}All providers are working") @@ -61,12 +61,6 @@ def create_response(_provider: type[BaseProvider]) -> str: ) return "".join(response) - -def judge(_provider: type[BaseProvider]) -> bool: - if _provider.needs_auth: - return _provider.working - - return test(_provider) def test(_provider: type[BaseProvider]) -> bool: try: -- cgit v1.2.3 From 38abb0a0b0a7f2e92dd5d19cee5374cc5a166f20 Mon Sep 17 00:00:00 2001 From: zengrr <47846202+zeng-rr@users.noreply.github.com> Date: Fri, 25 Aug 2023 10:07:48 +0800 Subject: Ails Supplementary Identification of Unusual Response Content --- g4f/Provider/Ails.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/g4f/Provider/Ails.py b/g4f/Provider/Ails.py index 806544b4..6665b677 100644 --- a/g4f/Provider/Ails.py +++ b/g4f/Provider/Ails.py @@ -72,7 +72,7 @@ class Ails(BaseProvider): if b"content" in token: completion_chunk = json.loads(token.decode().replace("data: ", "")) token = completion_chunk["choices"][0]["delta"].get("content") - if "ai.ls".lower() in token.lower(): + if "ai.ls" in token.lower() or "ai.ci" in token.lower(): raise Exception("Response Error: " + token) if token != None: yield token -- cgit v1.2.3 From 126496d3cacd06a4fa8cbb4e5bde417ce6bb5b4a Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Fri, 25 Aug 2023 06:41:32 +0200 Subject: Add OpenaiChat and Hugchat Provider Add tests for providers with auth Improve async support / 2x faster Shared get_cookies by domain function --- g4f/Provider/Bard.py | 22 ++-------- g4f/Provider/Bing.py | 86 +++++++++++++-------------------------- g4f/Provider/Hugchat.py | 67 ++++++++++++++++++++++++++++++ g4f/Provider/OpenaiChat.py | 74 +++++++++++++++++++++++++++++++++ g4f/Provider/__init__.py | 4 ++ g4f/Provider/base_provider.py | 85 +++++++++++++++++++++++++++++++++++++- testing/test_needs_auth.py | 95 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 354 insertions(+), 79 deletions(-) create mode 100644 g4f/Provider/Hugchat.py create mode 100644 g4f/Provider/OpenaiChat.py create mode 100644 testing/test_needs_auth.py diff --git a/g4f/Provider/Bard.py b/g4f/Provider/Bard.py index cbe728cd..a8c7d13f 100644 --- a/g4f/Provider/Bard.py +++ b/g4f/Provider/Bard.py @@ -2,42 +2,26 @@ import json import random import re -import browser_cookie3 from aiohttp import ClientSession import asyncio from ..typing import Any, CreateResult -from .base_provider import BaseProvider +from .base_provider import AsyncProvider, get_cookies -class Bard(BaseProvider): +class Bard(AsyncProvider): url = "https://bard.google.com" needs_auth = True working = True - @classmethod - def create_completion( - cls, - model: str, - messages: list[dict[str, str]], - stream: bool, - proxy: str = None, - cookies: dict = {}, - **kwargs: Any, - ) -> CreateResult: - yield asyncio.run(cls.create_async(str, messages, proxy, cookies)) - @classmethod async def create_async( cls, model: str, messages: list[dict[str, str]], proxy: str = None, - cookies: dict = {}, + cookies: dict = get_cookies(".google.com"), **kwargs: Any, ) -> str: - if not cookies: - for cookie in browser_cookie3.load(domain_name='.google.com'): - cookies[cookie.name] = cookie.value formatted = "\n".join( ["%s: %s" % (message["role"], message["content"]) for message in messages] diff --git a/g4f/Provider/Bing.py b/g4f/Provider/Bing.py index b9b9e9a4..2c2e60ad 100644 --- a/g4f/Provider/Bing.py +++ b/g4f/Provider/Bing.py @@ -5,48 +5,24 @@ import random import aiohttp import asyncio -import browser_cookie3 from aiohttp import ClientSession from ..typing import Any, AsyncGenerator, CreateResult, Union -from .base_provider import BaseProvider +from .base_provider import AsyncGeneratorProvider, get_cookies -class Bing(BaseProvider): +class Bing(AsyncGeneratorProvider): url = "https://bing.com/chat" + needs_auth = True working = True supports_gpt_4 = True - - @classmethod - def create_completion( - cls, - model: str, - messages: list[dict[str, str]], - stream: bool, - **kwargs: Any - ) -> CreateResult: - if stream: - yield from run(cls.create_async_generator(model, messages, **kwargs)) - else: - yield asyncio.run(cls.create_async(model, messages, **kwargs)) - - @classmethod - async def create_async( - cls, - model: str, - messages: list[dict[str, str]], - **kwargs: Any, - ) -> str: - result = [] - async for chunk in cls.create_async_generator(model, messages, **kwargs): - result.append(chunk) - if result: - return "".join(result) + supports_stream=True @staticmethod def create_async_generator( model: str, messages: list[dict[str, str]], - cookies: dict = {} + cookies: dict = get_cookies(".bing.com"), + **kwargs ) -> AsyncGenerator: if len(messages) < 2: prompt = messages[0]["content"] @@ -54,15 +30,11 @@ class Bing(BaseProvider): else: prompt = messages[-1]["content"] - context = convert(messages[:-1]) - - if not cookies: - for cookie in browser_cookie3.load(domain_name='.bing.com'): - cookies[cookie.name] = cookie.value + context = create_context(messages[:-1]) return stream_generate(prompt, context, cookies) -def convert(messages: list[dict[str, str]]): +def create_context(messages: list[dict[str, str]]): context = "" for message in messages: @@ -187,34 +159,32 @@ class Defaults: 'x-forwarded-for': ip_address, } - optionsSets = { - "optionsSets": [ - 'saharasugg', - 'enablenewsfc', - 'clgalileo', - 'gencontentv3', - "nlu_direct_response_filter", - "deepleo", - "disable_emoji_spoken_text", - "responsible_ai_policy_235", - "enablemm", - "h3precise" - "dtappid", - "cricinfo", - "cricinfov2", - "dv3sugg", - "nojbfedge" - ] - } + optionsSets = [ + 'saharasugg', + 'enablenewsfc', + 'clgalileo', + 'gencontentv3', + "nlu_direct_response_filter", + "deepleo", + "disable_emoji_spoken_text", + "responsible_ai_policy_235", + "enablemm", + "h3precise" + "dtappid", + "cricinfo", + "cricinfov2", + "dv3sugg", + "nojbfedge" + ] -def format_message(msg: dict) -> str: - return json.dumps(msg, ensure_ascii=False) + Defaults.delimiter +def format_message(message: dict) -> str: + return json.dumps(message, ensure_ascii=False) + Defaults.delimiter def create_message(conversation: Conversation, prompt: str, context: str=None) -> str: struct = { 'arguments': [ { - **Defaults.optionsSets, + 'optionsSets': Defaults.optionsSets, 'source': 'cib', 'allowedMessageTypes': Defaults.allowedMessageTypes, 'sliceIds': Defaults.sliceIds, diff --git a/g4f/Provider/Hugchat.py b/g4f/Provider/Hugchat.py new file mode 100644 index 00000000..cedf8402 --- /dev/null +++ b/g4f/Provider/Hugchat.py @@ -0,0 +1,67 @@ +has_module = False +try: + from hugchat.hugchat import ChatBot +except ImportError: + has_module = False + +from .base_provider import BaseProvider, get_cookies +from g4f.typing import CreateResult + +class Hugchat(BaseProvider): + url = "https://huggingface.co/chat/" + needs_auth = True + working = has_module + llms = ['OpenAssistant/oasst-sft-6-llama-30b-xor', 'meta-llama/Llama-2-70b-chat-hf'] + + @classmethod + def create_completion( + cls, + model: str, + messages: list[dict[str, str]], + stream: bool = False, + proxy: str = None, + cookies: str = get_cookies(".huggingface.co"), + **kwargs + ) -> CreateResult: + bot = ChatBot( + cookies=cookies + ) + + if proxy and "://" not in proxy: + proxy = f"http://{proxy}" + bot.session.proxies = {"http": proxy, "https": proxy} + + if model: + try: + if not isinstance(model, int): + model = cls.llms.index(model) + bot.switch_llm(model) + except: + raise RuntimeError(f"Model are not supported: {model}") + + if len(messages) > 1: + formatted = "\n".join( + ["%s: %s" % (message["role"], message["content"]) for message in messages] + ) + prompt = f"{formatted}\nAssistant:" + else: + prompt = messages.pop()["content"] + + try: + yield bot.chat(prompt, **kwargs) + finally: + bot.delete_conversation(bot.current_conversation) + bot.current_conversation = "" + pass + + @classmethod + @property + def params(cls): + params = [ + ("model", "str"), + ("messages", "list[dict[str, str]]"), + ("stream", "bool"), + ("proxy", "str"), + ] + param = ", ".join([": ".join(p) for p in params]) + return f"g4f.provider.{cls.__name__} supports: ({param})" diff --git a/g4f/Provider/OpenaiChat.py b/g4f/Provider/OpenaiChat.py new file mode 100644 index 00000000..cca258b3 --- /dev/null +++ b/g4f/Provider/OpenaiChat.py @@ -0,0 +1,74 @@ +has_module = True +try: + from revChatGPT.V1 import AsyncChatbot +except ImportError: + has_module = False +from .base_provider import AsyncGeneratorProvider, get_cookies +from ..typing import AsyncGenerator + +class OpenaiChat(AsyncGeneratorProvider): + url = "https://chat.openai.com" + needs_auth = True + working = has_module + supports_gpt_35_turbo = True + supports_gpt_4 = True + supports_stream = True + + @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 + ) -> AsyncGenerator: + + config = {"access_token": access_token, "model": model} + if proxy: + if "://" not in proxy: + proxy = f"http://{proxy}" + config["proxy"] = proxy + + bot = AsyncChatbot( + config=config + ) + + if not access_token: + cookies = cookies if cookies else get_cookies("chat.openai.com") + response = await bot.session.get("https://chat.openai.com/api/auth/session", cookies=cookies) + access_token = response.json()["accessToken"] + bot.set_access_token(access_token) + + if len(messages) > 1: + formatted = "\n".join( + ["%s: %s" % ((message["role"]).capitalize(), message["content"]) for message in messages] + ) + prompt = f"{formatted}\nAssistant:" + else: + prompt = messages.pop()["content"] + + returned = None + async for message in bot.ask(prompt): + message = message["message"] + if returned: + if message.startswith(returned): + new = message[len(returned):] + if new: + yield new + else: + yield message + returned = message + + @classmethod + @property + def params(cls): + params = [ + ("model", "str"), + ("messages", "list[dict[str, str]]"), + ("stream", "bool"), + ("proxy", "str"), + ] + param = ", ".join([": ".join(p) for p in params]) + return f"g4f.provider.{cls.__name__} supports: ({param})" diff --git a/g4f/Provider/__init__.py b/g4f/Provider/__init__.py index e27dee5d..5ad9f156 100644 --- a/g4f/Provider/__init__.py +++ b/g4f/Provider/__init__.py @@ -14,9 +14,11 @@ from .EasyChat import EasyChat from .Forefront import Forefront from .GetGpt import GetGpt from .H2o import H2o +from .Hugchat import Hugchat from .Liaobots import Liaobots from .Lockchat import Lockchat from .Opchatgpts import Opchatgpts +from .OpenaiChat import OpenaiChat from .Raycast import Raycast from .Theb import Theb from .Vercel import Vercel @@ -44,10 +46,12 @@ __all__ = [ "Forefront", "GetGpt", "H2o", + "Hugchat", "Liaobots", "Lockchat", "Opchatgpts", "Raycast", + "OpenaiChat", "Theb", "Vercel", "Wewordle", diff --git a/g4f/Provider/base_provider.py b/g4f/Provider/base_provider.py index 98ad3514..56d79ee6 100644 --- a/g4f/Provider/base_provider.py +++ b/g4f/Provider/base_provider.py @@ -1,7 +1,11 @@ from abc import ABC, abstractmethod -from ..typing import Any, CreateResult +from ..typing import Any, CreateResult, AsyncGenerator, Union +import browser_cookie3 +import asyncio +from time import time +import math class BaseProvider(ABC): url: str @@ -30,4 +34,81 @@ class BaseProvider(ABC): ("stream", "bool"), ] param = ", ".join([": ".join(p) for p in params]) - return f"g4f.provider.{cls.__name__} supports: ({param})" \ No newline at end of file + return f"g4f.provider.{cls.__name__} supports: ({param})" + + +_cookies = {} + +def get_cookies(cookie_domain: str) -> dict: + if cookie_domain not in _cookies: + _cookies[cookie_domain] = {} + for cookie in browser_cookie3.load(cookie_domain): + _cookies[cookie_domain][cookie.name] = cookie.value + return _cookies[cookie_domain] + + +class AsyncProvider(BaseProvider): + @classmethod + def create_completion( + cls, + model: str, + messages: list[dict[str, str]], + stream: bool = False, + **kwargs: Any + ) -> CreateResult: + yield asyncio.run(cls.create_async(model, messages, **kwargs)) + + @staticmethod + @abstractmethod + async def create_async( + model: str, + messages: list[dict[str, str]], + **kwargs: Any, + ) -> str: + raise NotImplementedError() + + +class AsyncGeneratorProvider(AsyncProvider): + @classmethod + def create_completion( + cls, + model: str, + messages: list[dict[str, str]], + stream: bool = True, + **kwargs: Any + ) -> CreateResult: + if stream: + yield from run_generator(cls.create_async_generator(model, messages, **kwargs)) + else: + yield from AsyncProvider.create_completion(cls=cls, model=model, messages=messages, **kwargs) + + @classmethod + async def create_async( + cls, + model: str, + messages: list[dict[str, str]], + **kwargs: Any, + ) -> str: + chunks = [chunk async for chunk in cls.create_async_generator(model, messages, **kwargs)] + if chunks: + return "".join(chunks) + + @staticmethod + @abstractmethod + def create_async_generator( + model: str, + messages: list[dict[str, str]], + ) -> AsyncGenerator: + raise NotImplementedError() + + +def run_generator(generator: AsyncGenerator[Union[Any, str], Any]): + loop = asyncio.new_event_loop() + gen = generator.__aiter__() + + while True: + try: + yield loop.run_until_complete(gen.__anext__()) + + except StopAsyncIteration: + break diff --git a/testing/test_needs_auth.py b/testing/test_needs_auth.py new file mode 100644 index 00000000..d44ed1df --- /dev/null +++ b/testing/test_needs_auth.py @@ -0,0 +1,95 @@ +import sys +from pathlib import Path +import asyncio +from time import time + +sys.path.append(str(Path(__file__).parent.parent)) + +import g4f + +providers = [g4f.Provider.OpenaiChat, g4f.Provider.Bard, g4f.Provider.Bing] + +# Async support +async def log_time_async(method: callable, **kwargs): + start = time() + result = await method(**kwargs) + secs = f"{round(time() - start, 2)} secs" + if result: + return " ".join([result, secs]) + return secs + +def log_time_yield(method: callable, **kwargs): + start = time() + result = yield from method(**kwargs) + yield f" {round(time() - start, 2)} secs" + +def log_time(method: callable, **kwargs): + start = time() + result = method(**kwargs) + secs = f"{round(time() - start, 2)} secs" + if result: + return " ".join([result, secs]) + return secs + +async def run_async(): + responses = [] + for provider in providers: + responses.append(log_time_async( + provider.create_async, + model=None, + messages=[{"role": "user", "content": "Hello"}], + log_time=True + )) + responses = await asyncio.gather(*responses) + for idx, provider in enumerate(providers): + print(f"{provider.__name__}:", responses[idx]) +print("Async Total:", asyncio.run(log_time_async(run_async))) + +# Streaming support: +def run_stream(): + for provider in providers: + print(f"{provider.__name__}: ", end="") + for response in log_time_yield( + provider.create_completion, + model=None, + messages=[{"role": "user", "content": "Hello"}], + ): + print(response, end="") + print() +print("Stream Total:", log_time(run_stream)) + +# No streaming support: +def create_completion(): + for provider in providers: + print(f"{provider.__name__}:", end=" ") + for response in log_time_yield( + g4f.Provider.Bard.create_completion, + model=None, + messages=[{"role": "user", "content": "Hello"}], + ): + print(response, end="") + print() +print("No Stream Total:", log_time(create_completion)) + +for response in g4f.Provider.Hugchat.create_completion( + model=None, + messages=[{"role": "user", "content": "Hello, tell about you."}], +): + print("Hugchat:", response) + +""" +OpenaiChat: Hello! How can I assist you today? 2.0 secs +Bard: Hello! How can I help you today? 3.44 secs +Bing: Hello, this is Bing. How can I help? 😊 4.14 secs +Async Total: 4.25 secs + +OpenaiChat: Hello! How can I assist you today? 1.85 secs +Bard: Hello! How can I help you today? 3.38 secs +Bing: Hello, this is Bing. How can I help? 😊 6.14 secs +Stream Total: 11.37 secs + +OpenaiChat: Hello! How can I help you today? 3.28 secs +Bard: Hello there! How can I help you today? 3.58 secs +Bing: Hello! How can I help you today? 3.28 secs +No Stream Total: 10.14 secs +""" \ No newline at end of file -- cgit v1.2.3 From c6b1a9a03bbfb33792c7ff2922d9319447b9b950 Mon Sep 17 00:00:00 2001 From: JunXiang Date: Fri, 25 Aug 2023 16:58:10 +0800 Subject: Add related project I've created a project that uses `gpt4free` for **auto translation** task. This action will automatically update and push README.md for different language. For example: 1. push `README.zh-TW.md` (zh-tw version) 2. use `gpt4free` to translate 3. generate the `README.md` (en version) 4. auto commit and push translating version. The [link](https://github.com/Lin-jun-xiang/action-translate-readme) has been added. --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 39b368cc..d78470e1 100644 --- a/README.md +++ b/README.md @@ -296,6 +296,13 @@ if __name__ == "__main__": Issues Pull Requests + + Action Translate Readme + Stars + Forks + Issues + Pull Requests + @@ -384,4 +391,4 @@ along with this program. If not, see . Star History Chart - \ No newline at end of file + -- cgit v1.2.3 From de42b60abaac8a6c31f30f1a56e891d2f14664b7 Mon Sep 17 00:00:00 2001 From: abc <98614666+xtekky@users.noreply.github.com> Date: Fri, 25 Aug 2023 17:24:24 +0100 Subject: ~ --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 10743750..d5c77d28 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh: with open("requirements.txt") as f: required = f.read().splitlines() -VERSION = '0.0.2.3' +VERSION = '0.0.2.4' DESCRIPTION = ( "The official gpt4free repository | various collection of powerful language models" ) -- cgit v1.2.3 From b953024f85bc78f39a5901bd914f436412c0953e Mon Sep 17 00:00:00 2001 From: abc <98614666+xtekky@users.noreply.github.com> Date: Fri, 25 Aug 2023 17:29:22 +0100 Subject: ~ --- testing/test_chat_completion.py | 2 +- tool/provider_init.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/test_chat_completion.py b/testing/test_chat_completion.py index d091d47b..32c069be 100644 --- a/testing/test_chat_completion.py +++ b/testing/test_chat_completion.py @@ -14,4 +14,4 @@ response = g4f.ChatCompletion.create( active_server=5, ) -print(response) \ No newline at end of file +print(response) diff --git a/tool/provider_init.py b/tool/provider_init.py index 22f21d4d..cd7f9333 100644 --- a/tool/provider_init.py +++ b/tool/provider_init.py @@ -30,4 +30,4 @@ def create_content(): if __name__ == "__main__": - main() + main() \ No newline at end of file -- cgit v1.2.3 From 567a0304ad6a1f0ca523b91f23c573f1770d0eb5 Mon Sep 17 00:00:00 2001 From: abc <98614666+xtekky@users.noreply.github.com> Date: Fri, 25 Aug 2023 17:29:33 +0100 Subject: ~| v-0.0.2.5 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d5c77d28..1a5defa0 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh: with open("requirements.txt") as f: required = f.read().splitlines() -VERSION = '0.0.2.4' +VERSION = '0.0.2.5' DESCRIPTION = ( "The official gpt4free repository | various collection of powerful language models" ) -- cgit v1.2.3 From bf3f0faa15f561ba2c007f5818526445a41b2f28 Mon Sep 17 00:00:00 2001 From: abc <98614666+xtekky@users.noreply.github.com> Date: Fri, 25 Aug 2023 17:30:10 +0100 Subject: ~ --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76c46ce5..e9380428 100644 --- a/README.md +++ b/README.md @@ -394,4 +394,4 @@ along with this program. If not, see . Star History Chart - + \ No newline at end of file -- cgit v1.2.3 From 5d08c7201fa5b4641f4277bf248c944b2c297b94 Mon Sep 17 00:00:00 2001 From: abc <98614666+xtekky@users.noreply.github.com> Date: Fri, 25 Aug 2023 17:30:59 +0100 Subject: ~ | v-0.0.2.5 --- g4f/typing.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/g4f/typing.py b/g4f/typing.py index 2e123112..dfe2cd2c 100644 --- a/g4f/typing.py +++ b/g4f/typing.py @@ -12,4 +12,4 @@ __all__ = [ "TypedDict", "SHA256", "CreateResult", -] +] \ No newline at end of file diff --git a/setup.py b/setup.py index 1a5defa0..8a33db8e 100644 --- a/setup.py +++ b/setup.py @@ -65,4 +65,4 @@ setup( "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", ], -) +) \ No newline at end of file -- cgit v1.2.3 From efd75a11b871d61ac31b0e274acdfb33daba361d Mon Sep 17 00:00:00 2001 From: abc <98614666+xtekky@users.noreply.github.com> Date: Sun, 27 Aug 2023 17:37:44 +0200 Subject: ~ | code styling --- g4f/Provider/AItianhu.py | 5 +- g4f/Provider/Acytoo.py | 36 +++--- g4f/Provider/Aichat.py | 10 +- g4f/Provider/Ails.py | 12 +- g4f/Provider/Bard.py | 4 +- g4f/Provider/Bing.py | 27 ++--- g4f/Provider/ChatgptAi.py | 66 +++++------ g4f/Provider/ChatgptLogin.py | 126 +++++++++----------- g4f/Provider/DeepAi.py | 23 ++-- g4f/Provider/DfeHub.py | 66 +++++------ g4f/Provider/EasyChat.py | 82 ++++++------- g4f/Provider/Equing.py | 64 +++++----- g4f/Provider/FastGpt.py | 66 +++++------ g4f/Provider/Forefront.py | 33 +++--- g4f/Provider/GetGpt.py | 97 +++++++-------- g4f/Provider/H2o.py | 76 ++++++------ g4f/Provider/Hugchat.py | 16 ++- g4f/Provider/Liaobots.py | 51 ++++---- g4f/Provider/Lockchat.py | 44 +++---- g4f/Provider/Opchatgpts.py | 70 ++++++----- g4f/Provider/OpenaiChat.py | 17 +-- g4f/Provider/Raycast.py | 19 ++- g4f/Provider/Theb.py | 86 +++++++------- g4f/Provider/V50.py | 55 ++++----- g4f/Provider/Vercel.py | 27 ++--- g4f/Provider/Wewordle.py | 79 ++++++------ g4f/Provider/You.py | 30 ++--- g4f/Provider/Yqcloud.py | 35 +++--- g4f/Provider/__init__.py | 123 +++++++++---------- g4f/Provider/base_provider.py | 40 +++---- g4f/__init__.py | 37 +++--- g4f/models.py | 270 +++++++++++++++++++----------------------- g4f/typing.py | 17 ++- 33 files changed, 842 insertions(+), 967 deletions(-) diff --git a/g4f/Provider/AItianhu.py b/g4f/Provider/AItianhu.py index 9f5440bc..abf66cc1 100644 --- a/g4f/Provider/AItianhu.py +++ b/g4f/Provider/AItianhu.py @@ -15,9 +15,8 @@ class AItianhu(BaseProvider): def create_completion( model: str, messages: list[dict[str, str]], - stream: bool, - **kwargs: Any, - ) -> CreateResult: + stream: bool, **kwargs: Any) -> CreateResult: + base = "" for message in messages: base += "%s: %s\n" % (message["role"], message["content"]) diff --git a/g4f/Provider/Acytoo.py b/g4f/Provider/Acytoo.py index 975e914b..5baa2b8d 100644 --- a/g4f/Provider/Acytoo.py +++ b/g4f/Provider/Acytoo.py @@ -7,8 +7,8 @@ from .base_provider import BaseProvider class Acytoo(BaseProvider): - url = "https://chat.acytoo.com/" - working = True + url = 'https://chat.acytoo.com/' + working = True supports_gpt_35_turbo = True @classmethod @@ -16,33 +16,33 @@ class Acytoo(BaseProvider): cls, model: str, messages: list[dict[str, str]], - stream: bool, - **kwargs: Any, - ) -> CreateResult: - headers = _create_header() - payload = _create_payload(messages, kwargs.get('temperature', 0.5)) + stream: bool, **kwargs: Any) -> CreateResult: - response = requests.post("{cls.url}api/completions", headers=headers, json=payload) + response = requests.post(f'{cls.url}api/completions', + headers=_create_header(), json=_create_payload(messages, kwargs.get('temperature', 0.5))) + response.raise_for_status() - response.encoding = "utf-8" + response.encoding = 'utf-8' + yield response.text def _create_header(): return { - "accept": "*/*", - "content-type": "application/json", + 'accept': '*/*', + 'content-type': 'application/json', } def _create_payload(messages: list[dict[str, str]], temperature): payload_messages = [ - message | {"createdAt": int(time.time()) * 1000} for message in messages + message | {'createdAt': int(time.time()) * 1000} for message in messages ] + return { - "key": "", - "model": "gpt-3.5-turbo", - "messages": payload_messages, - "temperature": temperature, - "password": "", - } + 'key' : '', + 'model' : 'gpt-3.5-turbo', + 'messages' : payload_messages, + 'temperature' : temperature, + 'password' : '' + } \ No newline at end of file diff --git a/g4f/Provider/Aichat.py b/g4f/Provider/Aichat.py index a1d90db7..62954e07 100644 --- a/g4f/Provider/Aichat.py +++ b/g4f/Provider/Aichat.py @@ -5,19 +5,17 @@ from .base_provider import BaseProvider class Aichat(BaseProvider): - url = "https://chat-gpt.org/chat" - working = True + url = "https://chat-gpt.org/chat" + working = True supports_gpt_35_turbo = True @staticmethod def create_completion( model: str, messages: list[dict[str, str]], - stream: bool, - **kwargs: Any, - ) -> CreateResult: + stream: bool, **kwargs: Any) -> CreateResult: + base = "" - for message in messages: base += "%s: %s\n" % (message["role"], message["content"]) base += "assistant:" diff --git a/g4f/Provider/Ails.py b/g4f/Provider/Ails.py index 6665b677..9a58d505 100644 --- a/g4f/Provider/Ails.py +++ b/g4f/Provider/Ails.py @@ -9,20 +9,18 @@ import requests from ..typing import SHA256, Any, CreateResult from .base_provider import BaseProvider - class Ails(BaseProvider): - url: str = "https://ai.ls" - working = True - supports_stream = True + url: str = "https://ai.ls" + working = True + supports_stream = True supports_gpt_35_turbo = True @staticmethod def create_completion( model: str, messages: list[dict[str, str]], - stream: bool, - **kwargs: Any, - ) -> CreateResult: + stream: bool, **kwargs: Any) -> CreateResult: + headers = { "authority": "api.caipacity.com", "accept": "*/*", diff --git a/g4f/Provider/Bard.py b/g4f/Provider/Bard.py index a8c7d13f..a516227b 100644 --- a/g4f/Provider/Bard.py +++ b/g4f/Provider/Bard.py @@ -19,9 +19,7 @@ class Bard(AsyncProvider): model: str, messages: list[dict[str, str]], proxy: str = None, - cookies: dict = get_cookies(".google.com"), - **kwargs: Any, - ) -> str: + cookies: dict = get_cookies(".google.com"), **kwargs: Any,) -> str: formatted = "\n".join( ["%s: %s" % (message["role"], message["content"]) for message in messages] diff --git a/g4f/Provider/Bing.py b/g4f/Provider/Bing.py index 2c2e60ad..fe4f9a58 100644 --- a/g4f/Provider/Bing.py +++ b/g4f/Provider/Bing.py @@ -1,29 +1,22 @@ -import asyncio -import json -import os -import random +import asyncio, aiohttp, json, os, random -import aiohttp -import asyncio -from aiohttp import ClientSession - -from ..typing import Any, AsyncGenerator, CreateResult, Union +from aiohttp import ClientSession +from ..typing import Any, AsyncGenerator, CreateResult, Union from .base_provider import AsyncGeneratorProvider, get_cookies class Bing(AsyncGeneratorProvider): - url = "https://bing.com/chat" - needs_auth = True - working = True - supports_gpt_4 = True - supports_stream=True + url = "https://bing.com/chat" + needs_auth = True + working = True + supports_gpt_4 = True + supports_stream = True @staticmethod def create_async_generator( model: str, messages: list[dict[str, str]], - cookies: dict = get_cookies(".bing.com"), - **kwargs - ) -> AsyncGenerator: + cookies: dict = get_cookies(".bing.com"), **kwargs) -> AsyncGenerator: + if len(messages) < 2: prompt = messages[0]["content"] context = None diff --git a/g4f/Provider/ChatgptAi.py b/g4f/Provider/ChatgptAi.py index 53518f65..13c591cb 100644 --- a/g4f/Provider/ChatgptAi.py +++ b/g4f/Provider/ChatgptAi.py @@ -1,23 +1,20 @@ -import re +import re, requests -import requests - -from ..typing import Any, CreateResult +from ..typing import Any, CreateResult from .base_provider import BaseProvider class ChatgptAi(BaseProvider): - url = "https://chatgpt.ai/gpt-4/" - working = True - supports_gpt_4 = True + url: str = "https://chatgpt.ai/gpt-4/" + working = True + supports_gpt_4 = True @staticmethod def create_completion( model: str, messages: list[dict[str, str]], - stream: bool, - **kwargs: Any, - ) -> CreateResult: + stream: bool, **kwargs: Any) -> CreateResult: + chat = "" for message in messages: chat += "%s: %s\n" % (message["role"], message["content"]) @@ -26,36 +23,35 @@ class ChatgptAi(BaseProvider): response = requests.get("https://chatgpt.ai/") nonce, post_id, _, bot_id = re.findall( r'data-nonce="(.*)"\n data-post-id="(.*)"\n data-url="(.*)"\n data-bot-id="(.*)"\n data-width', - response.text, - )[0] + response.text)[0] headers = { - "authority": "chatgpt.ai", - "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", - "cache-control": "no-cache", - "origin": "https://chatgpt.ai", - "pragma": "no-cache", - "referer": "https://chatgpt.ai/gpt-4/", - "sec-ch-ua": '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"', - "sec-ch-ua-mobile": "?0", - "sec-ch-ua-platform": '"Windows"', - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "same-origin", - "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", + "authority" : "chatgpt.ai", + "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", + "cache-control" : "no-cache", + "origin" : "https://chatgpt.ai", + "pragma" : "no-cache", + "referer" : "https://chatgpt.ai/gpt-4/", + "sec-ch-ua" : '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"', + "sec-ch-ua-mobile" : "?0", + "sec-ch-ua-platform" : '"Windows"', + "sec-fetch-dest" : "empty", + "sec-fetch-mode" : "cors", + "sec-fetch-site" : "same-origin", + "user-agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", } data = { - "_wpnonce": nonce, - "post_id": post_id, - "url": "https://chatgpt.ai/gpt-4", - "action": "wpaicg_chat_shortcode_message", - "message": chat, - "bot_id": bot_id, + "_wpnonce" : nonce, + "post_id" : post_id, + "url" : "https://chatgpt.ai/gpt-4", + "action" : "wpaicg_chat_shortcode_message", + "message" : chat, + "bot_id" : bot_id, } response = requests.post( - "https://chatgpt.ai/wp-admin/admin-ajax.php", headers=headers, data=data - ) + "https://chatgpt.ai/wp-admin/admin-ajax.php", headers=headers, data=data) + response.raise_for_status() - yield response.json()["data"] + yield response.json()["data"] \ No newline at end of file diff --git a/g4f/Provider/ChatgptLogin.py b/g4f/Provider/ChatgptLogin.py index da9fda40..d445e023 100644 --- a/g4f/Provider/ChatgptLogin.py +++ b/g4f/Provider/ChatgptLogin.py @@ -1,69 +1,62 @@ -import base64 -import os -import re +import base64, os, re, requests -import requests - -from ..typing import Any, CreateResult +from ..typing import Any, CreateResult from .base_provider import BaseProvider class ChatgptLogin(BaseProvider): - url = "https://opchatgpts.net" + url = "https://opchatgpts.net" supports_gpt_35_turbo = True - working = True + working = True @staticmethod def create_completion( model: str, messages: list[dict[str, str]], - stream: bool, - **kwargs: Any, - ) -> CreateResult: + stream: bool, **kwargs: Any) -> CreateResult: + headers = { - "authority": "chatgptlogin.ac", - "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://opchatgpts.net", - "referer": "https://opchatgpts.net/chatgpt-free-use/", - "sec-ch-ua": '"Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"', - "sec-ch-ua-mobile": "?0", - "sec-ch-ua-platform": '"Windows"', - "sec-fetch-dest": "empty", - "sec-fetch-mode": "cors", - "sec-fetch-site": "same-origin", - "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", - "x-wp-nonce": _get_nonce(), + "authority" : "chatgptlogin.ac", + "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://opchatgpts.net", + "referer" : "https://opchatgpts.net/chatgpt-free-use/", + "sec-ch-ua" : '"Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"', + "sec-ch-ua-mobile" : "?0", + "sec-ch-ua-platform" : '"Windows"', + "sec-fetch-dest" : "empty", + "sec-fetch-mode" : "cors", + "sec-fetch-site" : "same-origin", + "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", + "x-wp-nonce" : _get_nonce(), } conversation = _transform(messages) json_data = { - "env": "chatbot", - "session": "N/A", - "prompt": "Converse as if you were an AI assistant. Be friendly, creative.", - "context": "Converse as if you were an AI assistant. Be friendly, creative.", - "messages": conversation, - "newMessage": messages[-1]["content"], - "userName": '
User:
', - "aiName": '
AI:
', - "model": "gpt-3.5-turbo", - "temperature": kwargs.get("temperature", 0.8), - "maxTokens": 1024, - "maxResults": 1, - "apiKey": "", - "service": "openai", + "env" : "chatbot", + "session" : "N/A", + "prompt" : "Converse as if you were an AI assistant. Be friendly, creative.", + "context" : "Converse as if you were an AI assistant. Be friendly, creative.", + "messages" : conversation, + "newMessage" : messages[-1]["content"], + "userName" : '
User:
', + "aiName" : '
AI:
', + "model" : "gpt-3.5-turbo", + "temperature" : kwargs.get("temperature", 0.8), + "maxTokens" : 1024, + "maxResults" : 1, + "apiKey" : "", + "service" : "openai", "embeddingsIndex": "", - "stop": "", - "clientId": os.urandom(6).hex(), + "stop" : "", + "clientId" : os.urandom(6).hex() } - response = requests.post( - "https://opchatgpts.net/wp-json/ai-chatbot/v1/chat", - headers=headers, - json=json_data, - ) + response = requests.post("https://opchatgpts.net/wp-json/ai-chatbot/v1/chat", + headers=headers, json=json_data) + response.raise_for_status() yield response.json()["reply"] @@ -81,24 +74,21 @@ class ChatgptLogin(BaseProvider): def _get_nonce() -> str: - res = requests.get( - "https://opchatgpts.net/chatgpt-free-use/", - headers={ - "Referer": "https://opchatgpts.net/chatgpt-free-use/", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36", - }, - ) + res = requests.get("https://opchatgpts.net/chatgpt-free-use/", + headers = { + "Referer" : "https://opchatgpts.net/chatgpt-free-use/", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"}) result = re.search( r'class="mwai-chat mwai-chatgpt">.*Send