From 13e89d6ab9e3016741fdcbd03cc4996faec54f9a Mon Sep 17 00:00:00 2001 From: Heiner Lohaus Date: Sun, 22 Oct 2023 08:57:31 +0200 Subject: Fix MyShell Provider --- g4f/Provider/FakeGpt.py | 4 +- g4f/Provider/Geekgpt.py | 13 +-- g4f/Provider/Liaobots.py | 2 +- g4f/Provider/MyShell.py | 89 +++++++++++++++ g4f/Provider/Myshell.py | 219 ------------------------------------ g4f/Provider/Vercel.py | 8 +- g4f/Provider/Yqcloud.py | 11 +- g4f/Provider/__init__.py | 4 +- g4f/Provider/deprecated/Myshell.py | 219 ++++++++++++++++++++++++++++++++++++ g4f/Provider/deprecated/__init__.py | 3 +- g4f/models.py | 7 -- 11 files changed, 332 insertions(+), 247 deletions(-) create mode 100644 g4f/Provider/MyShell.py delete mode 100644 g4f/Provider/Myshell.py create mode 100644 g4f/Provider/deprecated/Myshell.py (limited to 'g4f') diff --git a/g4f/Provider/FakeGpt.py b/g4f/Provider/FakeGpt.py index 43298a4c..5bce1280 100644 --- a/g4f/Provider/FakeGpt.py +++ b/g4f/Provider/FakeGpt.py @@ -83,8 +83,8 @@ class FakeGpt(AsyncGeneratorProvider): line = json.loads(line) if line["message"]["metadata"]["message_type"] == "next": new_message = line["message"]["content"]["parts"][0] - yield new_message[len(last_message):] - last_message = new_message + yield new_message[len(last_message):] + last_message = new_message except: continue if not last_message: diff --git a/g4f/Provider/Geekgpt.py b/g4f/Provider/Geekgpt.py index 1a82757c..3bbc0e75 100644 --- a/g4f/Provider/Geekgpt.py +++ b/g4f/Provider/Geekgpt.py @@ -21,12 +21,12 @@ class GeekGpt(BaseProvider): json_data = { 'messages': messages, - 'model': model, - 'temperature': kwargs.get('temperature', 0.9), - 'presence_penalty': kwargs.get('presence_penalty', 0), - 'top_p': kwargs.get('top_p', 1), - 'frequency_penalty': kwargs.get('frequency_penalty', 0), - 'stream': True + 'model': model, + 'temperature': kwargs.get('temperature', 0.9), + 'presence_penalty': kwargs.get('presence_penalty', 0), + 'top_p': kwargs.get('top_p', 1), + 'frequency_penalty': kwargs.get('frequency_penalty', 0), + 'stream': True } data = dumps(json_data, separators=(',', ':')) @@ -61,7 +61,6 @@ class GeekGpt(BaseProvider): try: content = json.loads(json_data)["choices"][0]["delta"].get("content") - except Exception as e: raise RuntimeError(f'error | {e} :', json_data) diff --git a/g4f/Provider/Liaobots.py b/g4f/Provider/Liaobots.py index 72731728..740be856 100644 --- a/g4f/Provider/Liaobots.py +++ b/g4f/Provider/Liaobots.py @@ -30,7 +30,7 @@ models = { class Liaobots(AsyncGeneratorProvider): url = "https://liaobots.site" - working = False + working = True supports_gpt_35_turbo = True supports_gpt_4 = True _auth_code = None diff --git a/g4f/Provider/MyShell.py b/g4f/Provider/MyShell.py new file mode 100644 index 00000000..fefd08f4 --- /dev/null +++ b/g4f/Provider/MyShell.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +import time, random, json + +from ..requests import StreamSession +from ..typing import AsyncResult, Messages +from .base_provider import AsyncGeneratorProvider +from .helper import format_prompt + +class MyShell(AsyncGeneratorProvider): + url = "https://api.myshell.ai/v1/bot/chat/send_message" + + @classmethod + async def create_async_generator( + cls, + model: str, + messages: Messages, + proxy: str = None, + timeout: int = 120, + **kwargs + ) -> AsyncResult: + user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" + headers = { + "User-Agent": user_agent, + "Myshell-Service-Name": "organics-api", + "Visitor-Id": generate_visitor_id(user_agent) + } + async with StreamSession( + impersonate="chrome107", + proxies={"https": proxy}, + timeout=timeout, + headers=headers + ) as session: + prompt = format_prompt(messages) + data = { + "botId": "1", + "conversation_scenario": 3, + "message": prompt, + "messageType": 1 + } + async with session.post(cls.url, json=data) as response: + response.raise_for_status() + event = None + async for line in response.iter_lines(): + if line.startswith(b"event: "): + event = line[7:] + elif event == b"MESSAGE_REPLY_SSE_ELEMENT_EVENT_NAME_TEXT": + if line.startswith(b"data: "): + yield json.loads(line[6:])["content"] + if event == b"MESSAGE_REPLY_SSE_ELEMENT_EVENT_NAME_TEXT_STREAM_PUSH_FINISHED": + break + + +def xor_hash(B: str): + r = [] + i = 0 + + def o(e, t): + o_val = 0 + for i in range(len(t)): + o_val |= r[i] << (8 * i) + return e ^ o_val + + for e in range(len(B)): + t = ord(B[e]) + r.insert(0, 255 & t) + + if len(r) >= 4: + i = o(i, r) + r = [] + + if len(r) > 0: + i = o(i, r) + + return hex(i)[2:] + +def performance() -> str: + t = int(time.time() * 1000) + e = 0 + while t == int(time.time() * 1000): + e += 1 + return hex(t)[2:] + hex(e)[2:] + +def generate_visitor_id(user_agent: str) -> str: + f = performance() + r = hex(int(random.random() * (16**16)))[2:-2] + d = xor_hash(user_agent) + e = hex(1080 * 1920)[2:] + return f"{f}-{r}-{d}-{e}-{f}" \ No newline at end of file diff --git a/g4f/Provider/Myshell.py b/g4f/Provider/Myshell.py deleted file mode 100644 index 096545f9..00000000 --- a/g4f/Provider/Myshell.py +++ /dev/null @@ -1,219 +0,0 @@ -# not using WS anymore - -from __future__ import annotations - -import json, uuid, hashlib, time, random - -from aiohttp import ClientSession -from aiohttp.http import WSMsgType -import asyncio - -from ..typing import AsyncResult, Messages -from .base_provider import AsyncGeneratorProvider, format_prompt - - -models = { - "samantha": "1e3be7fe89e94a809408b1154a2ee3e1", - "gpt-3.5-turbo": "8077335db7cd47e29f7de486612cc7fd", - "gpt-4": "01c8de4fbfc548df903712b0922a4e01", -} - - -class Myshell(AsyncGeneratorProvider): - url = "https://app.myshell.ai/chat" - working = False - supports_gpt_35_turbo = True - supports_gpt_4 = True - - @classmethod - async def create_async_generator( - cls, - model: str, - messages: Messages, - proxy: str = None, - timeout: int = 90, - **kwargs - ) -> AsyncResult: - if not model: - bot_id = models["samantha"] - elif model in models: - bot_id = models[model] - else: - raise ValueError(f"Model are not supported: {model}") - - 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' - visitor_id = generate_visitor_id(user_agent) - - async with ClientSession( - headers={'User-Agent': user_agent} - ) as session: - async with session.ws_connect( - "wss://api.myshell.ai/ws/?EIO=4&transport=websocket", - autoping=False, - timeout=timeout, - proxy=proxy - ) as wss: - # Send and receive hello message - await wss.receive_str() - message = json.dumps({"token": None, "visitorId": visitor_id}) - await wss.send_str(f"40/chat,{message}") - await wss.receive_str() - - # Fix "need_verify_captcha" issue - await asyncio.sleep(5) - - # Create chat message - text = format_prompt(messages) - chat_data = json.dumps(["text_chat",{ - "reqId": str(uuid.uuid4()), - "botUid": bot_id, - "sourceFrom": "myshellWebsite", - "text": text, - **generate_signature(text) - }]) - - # Send chat message - chat_start = "42/chat," - chat_message = f"{chat_start}{chat_data}" - await wss.send_str(chat_message) - - # Receive messages - async for message in wss: - if message.type != WSMsgType.TEXT: - continue - # Ping back - if message.data == "2": - await wss.send_str("3") - continue - # Is not chat message - if not message.data.startswith(chat_start): - continue - data_type, data = json.loads(message.data[len(chat_start):]) - if data_type == "text_stream": - if data["data"]["text"]: - yield data["data"]["text"] - elif data["data"]["isFinal"]: - break - elif data_type in ("message_replied", "need_verify_captcha"): - raise RuntimeError(f"Received unexpected message: {data_type}") - - - @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})" - - -def generate_timestamp() -> str: - return str( - int( - str(int(time.time() * 1000))[:-1] - + str( - sum( - 2 * int(digit) - if idx % 2 == 0 - else 3 * int(digit) - for idx, digit in enumerate(str(int(time.time() * 1000))[:-1]) - ) - % 10 - ) - ) - ) - -def generate_signature(text: str): - timestamp = generate_timestamp() - version = 'v1.0.0' - secret = '8@VXGK3kKHr!u2gA' - data = f"{version}#{text}#{timestamp}#{secret}" - signature = hashlib.md5(data.encode()).hexdigest() - signature = signature[::-1] - return { - "signature": signature, - "timestamp": timestamp, - "version": version - } - -def xor_hash(B: str): - r = [] - i = 0 - - def o(e, t): - o_val = 0 - for i in range(len(t)): - o_val |= r[i] << (8 * i) - return e ^ o_val - - for e in range(len(B)): - t = ord(B[e]) - r.insert(0, 255 & t) - - if len(r) >= 4: - i = o(i, r) - r = [] - - if len(r) > 0: - i = o(i, r) - - return hex(i)[2:] - -def performance() -> str: - t = int(time.time() * 1000) - e = 0 - while t == int(time.time() * 1000): - e += 1 - return hex(t)[2:] + hex(e)[2:] - -def generate_visitor_id(user_agent: str) -> str: - f = performance() - r = hex(int(random.random() * (16**16)))[2:-2] - d = xor_hash(user_agent) - e = hex(1080 * 1920)[2:] - return f"{f}-{r}-{d}-{e}-{f}" - - - -# update -# from g4f.requests import StreamSession - -# async def main(): -# headers = { -# 'authority': 'api.myshell.ai', -# 'accept': 'application/json', -# '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', -# 'myshell-service-name': 'organics-api', -# 'origin': 'https://app.myshell.ai', -# 'referer': 'https://app.myshell.ai/', -# '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-site', -# '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', -# 'visitor-id': '18ae8fe5d916d3-0213f29594b17f-18525634-157188-18ae8fe5d916d3', -# } - -# json_data = { -# 'conversation_scenario': 3, -# 'botId': '4738', -# 'message': 'hi', -# 'messageType': 1, -# } - -# async with StreamSession(headers=headers, impersonate="chrome110") as session: -# async with session.post(f'https://api.myshell.ai/v1/bot/chat/send_message', -# json=json_data) as response: - -# response.raise_for_status() -# async for chunk in response.iter_content(): -# print(chunk.decode("utf-8")) - -# import asyncio -# asyncio.run(main()) \ No newline at end of file diff --git a/g4f/Provider/Vercel.py b/g4f/Provider/Vercel.py index 10130320..7c3b8c55 100644 --- a/g4f/Provider/Vercel.py +++ b/g4f/Provider/Vercel.py @@ -4,7 +4,6 @@ import json, base64, requests, execjs, random, uuid from ..typing import Messages, TypedDict, CreateResult, Any from .base_provider import BaseProvider -from abc import abstractmethod from ..debug import logging @@ -15,12 +14,13 @@ class Vercel(BaseProvider): supports_stream = True @staticmethod - @abstractmethod def create_completion( model: str, messages: Messages, stream: bool, - proxy: str = None, **kwargs) -> CreateResult: + proxy: str = None, + **kwargs + ) -> CreateResult: if not model: model = "gpt-3.5-turbo" @@ -65,7 +65,7 @@ class Vercel(BaseProvider): headers=headers, json=json_data, stream=True, proxies={"https": proxy}) try: response.raise_for_status() - except Exception: + except: continue for token in response.iter_content(chunk_size=None): yield token.decode() diff --git a/g4f/Provider/Yqcloud.py b/g4f/Provider/Yqcloud.py index d6ce21a9..b567f3a0 100644 --- a/g4f/Provider/Yqcloud.py +++ b/g4f/Provider/Yqcloud.py @@ -1,7 +1,7 @@ from __future__ import annotations import random -from aiohttp import ClientSession +from ..requests import StreamSession from ..typing import AsyncResult, Messages from .base_provider import AsyncGeneratorProvider, format_prompt @@ -19,13 +19,13 @@ class Yqcloud(AsyncGeneratorProvider): proxy: str = None, **kwargs, ) -> AsyncResult: - async with ClientSession( - headers=_create_header() + async with StreamSession( + headers=_create_header(), proxies={"https": proxy} ) as session: payload = _create_payload(messages, **kwargs) - async with session.post("https://api.aichatos.cloud/api/generateStream", proxy=proxy, json=payload) as response: + async with session.post("https://api.aichatos.cloud/api/generateStream", json=payload) as response: response.raise_for_status() - async for chunk in response.content.iter_any(): + async for chunk in response.iter_content(): if chunk: chunk = chunk.decode() if "sorry, 您的ip已由于触发防滥用检测而被封禁" in chunk: @@ -38,6 +38,7 @@ def _create_header(): "accept" : "application/json, text/plain, */*", "content-type" : "application/json", "origin" : "https://chat9.yqcloud.top", + "referer" : "https://chat9.yqcloud.top/" } diff --git a/g4f/Provider/__init__.py b/g4f/Provider/__init__.py index a465b428..97351120 100644 --- a/g4f/Provider/__init__.py +++ b/g4f/Provider/__init__.py @@ -26,7 +26,7 @@ from .GptGo import GptGo from .GptGod import GptGod from .Liaobots import Liaobots from .Llama2 import Llama2 -from .Myshell import Myshell +from .MyShell import MyShell from .NoowAi import NoowAi from .Opchatgpts import Opchatgpts from .Phind import Phind @@ -90,6 +90,7 @@ class ProviderUtils: 'Lockchat': Lockchat, 'MikuChat': MikuChat, 'Myshell': Myshell, + 'MyShell': MyShell, 'NoowAi': NoowAi, 'Opchatgpts': Opchatgpts, 'OpenAssistant': OpenAssistant, @@ -159,6 +160,7 @@ __all__ = [ 'Llama2', 'Lockchat', 'Myshell', + 'MyShell', 'NoowAi', 'Opchatgpts', 'Raycast', diff --git a/g4f/Provider/deprecated/Myshell.py b/g4f/Provider/deprecated/Myshell.py new file mode 100644 index 00000000..b1aa2b2d --- /dev/null +++ b/g4f/Provider/deprecated/Myshell.py @@ -0,0 +1,219 @@ +# not using WS anymore + +from __future__ import annotations + +import json, uuid, hashlib, time, random + +from aiohttp import ClientSession +from aiohttp.http import WSMsgType +import asyncio + +from ...typing import AsyncResult, Messages +from ..base_provider import AsyncGeneratorProvider, format_prompt + + +models = { + "samantha": "1e3be7fe89e94a809408b1154a2ee3e1", + "gpt-3.5-turbo": "8077335db7cd47e29f7de486612cc7fd", + "gpt-4": "01c8de4fbfc548df903712b0922a4e01", +} + + +class Myshell(AsyncGeneratorProvider): + url = "https://app.myshell.ai/chat" + working = False + supports_gpt_35_turbo = True + supports_gpt_4 = True + + @classmethod + async def create_async_generator( + cls, + model: str, + messages: Messages, + proxy: str = None, + timeout: int = 90, + **kwargs + ) -> AsyncResult: + if not model: + bot_id = models["samantha"] + elif model in models: + bot_id = models[model] + else: + raise ValueError(f"Model are not supported: {model}") + + 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' + visitor_id = generate_visitor_id(user_agent) + + async with ClientSession( + headers={'User-Agent': user_agent} + ) as session: + async with session.ws_connect( + "wss://api.myshell.ai/ws/?EIO=4&transport=websocket", + autoping=False, + timeout=timeout, + proxy=proxy + ) as wss: + # Send and receive hello message + await wss.receive_str() + message = json.dumps({"token": None, "visitorId": visitor_id}) + await wss.send_str(f"40/chat,{message}") + await wss.receive_str() + + # Fix "need_verify_captcha" issue + await asyncio.sleep(5) + + # Create chat message + text = format_prompt(messages) + chat_data = json.dumps(["text_chat",{ + "reqId": str(uuid.uuid4()), + "botUid": bot_id, + "sourceFrom": "myshellWebsite", + "text": text, + **generate_signature(text) + }]) + + # Send chat message + chat_start = "42/chat," + chat_message = f"{chat_start}{chat_data}" + await wss.send_str(chat_message) + + # Receive messages + async for message in wss: + if message.type != WSMsgType.TEXT: + continue + # Ping back + if message.data == "2": + await wss.send_str("3") + continue + # Is not chat message + if not message.data.startswith(chat_start): + continue + data_type, data = json.loads(message.data[len(chat_start):]) + if data_type == "text_stream": + if data["data"]["text"]: + yield data["data"]["text"] + elif data["data"]["isFinal"]: + break + elif data_type in ("message_replied", "need_verify_captcha"): + raise RuntimeError(f"Received unexpected message: {data_type}") + + + @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})" + + +def generate_timestamp() -> str: + return str( + int( + str(int(time.time() * 1000))[:-1] + + str( + sum( + 2 * int(digit) + if idx % 2 == 0 + else 3 * int(digit) + for idx, digit in enumerate(str(int(time.time() * 1000))[:-1]) + ) + % 10 + ) + ) + ) + +def generate_signature(text: str): + timestamp = generate_timestamp() + version = 'v1.0.0' + secret = '8@VXGK3kKHr!u2gA' + data = f"{version}#{text}#{timestamp}#{secret}" + signature = hashlib.md5(data.encode()).hexdigest() + signature = signature[::-1] + return { + "signature": signature, + "timestamp": timestamp, + "version": version + } + +def xor_hash(B: str): + r = [] + i = 0 + + def o(e, t): + o_val = 0 + for i in range(len(t)): + o_val |= r[i] << (8 * i) + return e ^ o_val + + for e in range(len(B)): + t = ord(B[e]) + r.insert(0, 255 & t) + + if len(r) >= 4: + i = o(i, r) + r = [] + + if len(r) > 0: + i = o(i, r) + + return hex(i)[2:] + +def performance() -> str: + t = int(time.time() * 1000) + e = 0 + while t == int(time.time() * 1000): + e += 1 + return hex(t)[2:] + hex(e)[2:] + +def generate_visitor_id(user_agent: str) -> str: + f = performance() + r = hex(int(random.random() * (16**16)))[2:-2] + d = xor_hash(user_agent) + e = hex(1080 * 1920)[2:] + return f"{f}-{r}-{d}-{e}-{f}" + + + +# update +# from g4f.requests import StreamSession + +# async def main(): +# headers = { +# 'authority': 'api.myshell.ai', +# 'accept': 'application/json', +# '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', +# 'myshell-service-name': 'organics-api', +# 'origin': 'https://app.myshell.ai', +# 'referer': 'https://app.myshell.ai/', +# '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-site', +# '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', +# 'visitor-id': '18ae8fe5d916d3-0213f29594b17f-18525634-157188-18ae8fe5d916d3', +# } + +# json_data = { +# 'conversation_scenario': 3, +# 'botId': '4738', +# 'message': 'hi', +# 'messageType': 1, +# } + +# async with StreamSession(headers=headers, impersonate="chrome110") as session: +# async with session.post(f'https://api.myshell.ai/v1/bot/chat/send_message', +# json=json_data) as response: + +# response.raise_for_status() +# async for chunk in response.iter_content(): +# print(chunk.decode("utf-8")) + +# import asyncio +# asyncio.run(main()) \ No newline at end of file diff --git a/g4f/Provider/deprecated/__init__.py b/g4f/Provider/deprecated/__init__.py index db48c3fb..f8e35b37 100644 --- a/g4f/Provider/deprecated/__init__.py +++ b/g4f/Provider/deprecated/__init__.py @@ -12,4 +12,5 @@ from .V50 import V50 from .FastGpt import FastGpt from .Aivvm import Aivvm from .Vitalentum import Vitalentum -from .H2o import H2o \ No newline at end of file +from .H2o import H2o +from .Myshell import Myshell \ No newline at end of file diff --git a/g4f/models.py b/g4f/models.py index 22a04ffb..7eee917a 100644 --- a/g4f/models.py +++ b/g4f/models.py @@ -3,18 +3,13 @@ from dataclasses import dataclass from .typing import Union from .Provider import BaseProvider, RetryProvider from .Provider import ( - ChatgptLogin, - ChatgptDuo, GptForLove, ChatgptAi, GptChatly, - Liaobots, ChatgptX, ChatBase, - Yqcloud, GeekGpt, FakeGpt, - Myshell, FreeGpt, NoowAi, Vercel, @@ -23,9 +18,7 @@ from .Provider import ( AiAsk, GptGo, Phind, - Ylokh, Bard, - Aibn, Bing, You, H2o, -- cgit v1.2.3