Merge pull request #1846 from hlohaus/nem

Updates for some providers
This commit is contained in:
H Lohaus 2024-04-17 10:43:11 +02:00 committed by GitHub
commit 6afc6722a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 121 additions and 26 deletions

View File

@ -107,7 +107,7 @@ def get_default_cookies():
'PPLState' : '1', 'PPLState' : '1',
'KievRPSSecAuth': '', 'KievRPSSecAuth': '',
'SUID' : '', 'SUID' : '',
'SRCHUSR' : '', 'SRCHUSR' : f'DOB={date.today().strftime("%Y%m%d")}&T={int(time.time())}',
'SRCHHPGUSR' : f'HV={int(time.time())}', 'SRCHHPGUSR' : f'HV={int(time.time())}',
'BCP' : 'AD=1&AL=1&SM=1', 'BCP' : 'AD=1&AL=1&SM=1',
'_Rwho' : f'u=d&ts={date.today().isoformat()}', '_Rwho' : f'u=d&ts={date.today().isoformat()}',

View File

@ -6,6 +6,7 @@ from aiohttp import ClientSession
from ..typing import Messages, AsyncResult from ..typing import Messages, AsyncResult
from ..requests import get_args_from_browser from ..requests import get_args_from_browser
from ..webdriver import WebDriver
from .base_provider import AsyncGeneratorProvider from .base_provider import AsyncGeneratorProvider
from .helper import get_random_string from .helper import get_random_string
@ -23,9 +24,10 @@ class Chatgpt4Online(AsyncGeneratorProvider):
model: str, model: str,
messages: Messages, messages: Messages,
proxy: str = None, proxy: str = None,
webdriver: WebDriver = None,
**kwargs **kwargs
) -> AsyncResult: ) -> AsyncResult:
args = get_args_from_browser(f"{cls.url}/chat/", proxy=proxy) args = get_args_from_browser(f"{cls.url}/chat/", webdriver, proxy=proxy)
async with ClientSession(**args) as session: async with ClientSession(**args) as session:
if not cls._wpnonce: if not cls._wpnonce:
async with session.get(f"{cls.url}/chat/", proxy=proxy) as response: async with session.get(f"{cls.url}/chat/", proxy=proxy) as response:

View File

@ -4,8 +4,10 @@ import json
import aiohttp import aiohttp
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
from .helper import get_connector
from ..typing import AsyncResult, Messages from ..typing import AsyncResult, Messages
from ..requests.raise_for_status import raise_for_status from ..requests.raise_for_status import raise_for_status
from ..providers.conversation import BaseConversation
class DuckDuckGo(AsyncGeneratorProvider, ProviderModelMixin): class DuckDuckGo(AsyncGeneratorProvider, ProviderModelMixin):
url = "https://duckduckgo.com/duckchat" url = "https://duckduckgo.com/duckchat"
@ -42,23 +44,39 @@ class DuckDuckGo(AsyncGeneratorProvider, ProviderModelMixin):
cls, cls,
model: str, model: str,
messages: Messages, messages: Messages,
proxy: str = None,
connector: aiohttp.BaseConnector = None,
conversation: Conversation = None,
return_conversation: bool = False,
**kwargs **kwargs
) -> AsyncResult: ) -> AsyncResult:
async with aiohttp.ClientSession(headers=cls.headers) as session: async with aiohttp.ClientSession(headers=cls.headers, connector=get_connector(connector, proxy)) as session:
async with session.get(cls.status_url, headers={"x-vqd-accept": "1"}) as response: if conversation is not None and len(messages) > 1:
await raise_for_status(response) vqd_4 = conversation.vqd_4
vqd_4 = response.headers.get("x-vqd-4") messages = [*conversation.messages, messages[-2], messages[-1]]
else:
async with session.get(cls.status_url, headers={"x-vqd-accept": "1"}) as response:
await raise_for_status(response)
vqd_4 = response.headers.get("x-vqd-4")
messages = [messages[-1]]
payload = { payload = {
'model': cls.get_model(model), 'model': cls.get_model(model),
'messages': messages 'messages': messages
} }
async with session.post(cls.chat_url, json=payload, headers={"x-vqd-4": vqd_4}) as response: async with session.post(cls.chat_url, json=payload, headers={"x-vqd-4": vqd_4}) as response:
await raise_for_status(response) await raise_for_status(response)
if return_conversation:
yield Conversation(response.headers.get("x-vqd-4"), messages)
async for line in response.content: async for line in response.content:
if line.startswith(b"data: "): if line.startswith(b"data: "):
chunk = line[6:] chunk = line[6:]
if chunk.startswith(b"[DONE]"): if chunk.startswith(b"[DONE]"):
break break
data = json.loads(chunk) data = json.loads(chunk)
if "message" in data: if "message" in data and data["message"]:
yield data["message"] yield data["message"]
class Conversation(BaseConversation):
def __init__(self, vqd_4: str, messages: Messages) -> None:
self.vqd_4 = vqd_4
self.messages = messages

View File

@ -1,10 +1,13 @@
from __future__ import annotations from __future__ import annotations
import json import json
import time
import hashlib
from aiohttp import ClientSession from aiohttp import ClientSession
from ..typing import AsyncResult, Messages from ..typing import AsyncResult, Messages
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
from .helper import get_random_hex, get_random_string
from ..requests.raise_for_status import raise_for_status from ..requests.raise_for_status import raise_for_status
class FlowGpt(AsyncGeneratorProvider, ProviderModelMixin): class FlowGpt(AsyncGeneratorProvider, ProviderModelMixin):
@ -17,9 +20,17 @@ class FlowGpt(AsyncGeneratorProvider, ProviderModelMixin):
models = [ models = [
"gpt-3.5-turbo", "gpt-3.5-turbo",
"gpt-3.5-long", "gpt-3.5-long",
"gpt-4-turbo",
"google-gemini", "google-gemini",
"claude-instant",
"claude-v1",
"claude-v2", "claude-v2",
"llama2-13b" "llama2-13b",
"mythalion-13b",
"pygmalion-13b",
"chronos-hermes-13b",
"Mixtral-8x7B",
"Dolphin-2.6-8x7B"
] ]
model_aliases = { model_aliases = {
"gemini": "google-gemini", "gemini": "google-gemini",
@ -36,6 +47,12 @@ class FlowGpt(AsyncGeneratorProvider, ProviderModelMixin):
**kwargs **kwargs
) -> AsyncResult: ) -> AsyncResult:
model = cls.get_model(model) model = cls.get_model(model)
timestamp = str(int(time.time()))
auth = "Bearer null"
nonce = get_random_hex()
data = f"{timestamp}-{nonce}-{auth}"
signature = hashlib.md5(data.encode()).hexdigest()
headers = { headers = {
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0", "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0",
"Accept": "*/*", "Accept": "*/*",
@ -49,7 +66,12 @@ class FlowGpt(AsyncGeneratorProvider, ProviderModelMixin):
"Sec-Fetch-Dest": "empty", "Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors", "Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-site", "Sec-Fetch-Site": "same-site",
"TE": "trailers" "TE": "trailers",
"Authorization": auth,
"x-flow-device-id": f"f-{get_random_string(19)}",
"x-nonce": nonce,
"x-signature": signature,
"x-timestamp": timestamp
} }
async with ClientSession(headers=headers) as session: async with ClientSession(headers=headers) as session:
history = [message for message in messages[:-1] if message["role"] != "system"] history = [message for message in messages[:-1] if message["role"] != "system"]
@ -69,7 +91,7 @@ class FlowGpt(AsyncGeneratorProvider, ProviderModelMixin):
"generateImage": False, "generateImage": False,
"generateAudio": False "generateAudio": False
} }
async with session.post("https://backend-k8s.flowgpt.com/v2/chat-anonymous", json=data, proxy=proxy) as response: async with session.post("https://backend-k8s.flowgpt.com/v2/chat-anonymous-encrypted", json=data, proxy=proxy) as response:
await raise_for_status(response) await raise_for_status(response)
async for chunk in response.content: async for chunk in response.content:
if chunk.strip(): if chunk.strip():

View File

@ -2,14 +2,13 @@ from __future__ import annotations
import random import random
import json import json
from aiohttp import ClientSession, BaseConnector
from ..typing import AsyncResult, Messages from ..typing import AsyncResult, Messages
from ..requests import StreamSession, raise_for_status
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
from .helper import get_connector
API_URL = "https://labs-api.perplexity.ai/socket.io/" API_URL = "https://www.perplexity.ai/socket.io/"
WS_URL = "wss://labs-api.perplexity.ai/socket.io/" WS_URL = "wss://www.perplexity.ai/socket.io/"
class PerplexityLabs(AsyncGeneratorProvider, ProviderModelMixin): class PerplexityLabs(AsyncGeneratorProvider, ProviderModelMixin):
url = "https://labs.perplexity.ai" url = "https://labs.perplexity.ai"
@ -35,7 +34,6 @@ class PerplexityLabs(AsyncGeneratorProvider, ProviderModelMixin):
model: str, model: str,
messages: Messages, messages: Messages,
proxy: str = None, proxy: str = None,
connector: BaseConnector = None,
**kwargs **kwargs
) -> AsyncResult: ) -> AsyncResult:
headers = { headers = {
@ -51,21 +49,22 @@ class PerplexityLabs(AsyncGeneratorProvider, ProviderModelMixin):
"Sec-Fetch-Site": "same-site", "Sec-Fetch-Site": "same-site",
"TE": "trailers", "TE": "trailers",
} }
async with ClientSession(headers=headers, connector=get_connector(connector, proxy)) as session: async with StreamSession(headers=headers, proxies={"all": proxy}) as session:
t = format(random.getrandbits(32), "08x") t = format(random.getrandbits(32), "08x")
async with session.get( async with session.get(
f"{API_URL}?EIO=4&transport=polling&t={t}" f"{API_URL}?EIO=4&transport=polling&t={t}"
) as response: ) as response:
await raise_for_status(response)
text = await response.text() text = await response.text()
assert text.startswith("0")
sid = json.loads(text[1:])["sid"] sid = json.loads(text[1:])["sid"]
post_data = '40{"jwt":"anonymous-ask-user"}' post_data = '40{"jwt":"anonymous-ask-user"}'
async with session.post( async with session.post(
f"{API_URL}?EIO=4&transport=polling&t={t}&sid={sid}", f"{API_URL}?EIO=4&transport=polling&t={t}&sid={sid}",
data=post_data data=post_data
) as response: ) as response:
assert await response.text() == "OK" await raise_for_status(response)
assert await response.text() == "OK"
async with session.ws_connect(f"{WS_URL}?EIO=4&transport=websocket&sid={sid}", autoping=False) as ws: async with session.ws_connect(f"{WS_URL}?EIO=4&transport=websocket&sid={sid}", autoping=False) as ws:
await ws.send_str("2probe") await ws.send_str("2probe")
assert(await ws.receive_str() == "3probe") assert(await ws.receive_str() == "3probe")

View File

@ -34,9 +34,9 @@ async def create_conversation(session: ClientSession, headers: dict, tone: str)
Conversation: An instance representing the created conversation. Conversation: An instance representing the created conversation.
""" """
if tone == "Copilot": if tone == "Copilot":
url = "https://copilot.microsoft.com/turing/conversation/create?bundleVersion=1.1686.0" url = "https://copilot.microsoft.com/turing/conversation/create?bundleVersion=1.1690.0"
else: else:
url = "https://www.bing.com/turing/conversation/create?bundleVersion=1.1686.0" url = "https://www.bing.com/turing/conversation/create?bundleVersion=1.1690.0"
async with session.get(url, headers=headers) as response: async with session.get(url, headers=headers) as response:
if response.status == 404: if response.status == 404:
raise RateLimitError("Response 404: Do less requests and reuse conversations") raise RateLimitError("Response 404: Do less requests and reuse conversations")

View File

@ -60,6 +60,7 @@ class Gemini(AsyncGeneratorProvider):
model: str, model: str,
messages: Messages, messages: Messages,
proxy: str = None, proxy: str = None,
api_key: str = None,
cookies: Cookies = None, cookies: Cookies = None,
connector: BaseConnector = None, connector: BaseConnector = None,
image: ImageType = None, image: ImageType = None,
@ -67,6 +68,10 @@ class Gemini(AsyncGeneratorProvider):
**kwargs **kwargs
) -> AsyncResult: ) -> AsyncResult:
prompt = format_prompt(messages) prompt = format_prompt(messages)
if api_key is not None:
if cookies is None:
cookies = {}
cookies["__Secure-1PSID"] = api_key
cookies = cookies if cookies else get_cookies(".google.com", False, True) cookies = cookies if cookies else get_cookies(".google.com", False, True)
base_connector = get_connector(connector, proxy) base_connector = get_connector(connector, proxy)
async with ClientSession( async with ClientSession(

View File

@ -38,6 +38,9 @@
</script> </script>
<script src="https://unpkg.com/gpt-tokenizer/dist/cl100k_base.js" async></script> <script src="https://unpkg.com/gpt-tokenizer/dist/cl100k_base.js" async></script>
<script src="/static/js/text_to_speech/index.js" async></script> <script src="/static/js/text_to_speech/index.js" async></script>
<!--
<script src="/static/js/whisper-web/index.js" async></script>
-->
<script> <script>
const user_image = '<img src="/static/img/user.png" alt="your avatar">'; const user_image = '<img src="/static/img/user.png" alt="your avatar">';
const gpt_image = '<img src="/static/img/gpt.png" alt="your avatar">'; const gpt_image = '<img src="/static/img/gpt.png" alt="your avatar">';
@ -89,6 +92,7 @@
</div> </div>
<div class="settings hidden"> <div class="settings hidden">
<div class="paper"> <div class="paper">
<h3>Settings</h3>
<div class="field"> <div class="field">
<span class="label">Web Access</span> <span class="label">Web Access</span>
<input type="checkbox" id="switch" /> <input type="checkbox" id="switch" />
@ -127,7 +131,7 @@
</div> </div>
<div class="field box"> <div class="field box">
<label for="Gemini-api_key" class="label" title="">Gemini:</label> <label for="Gemini-api_key" class="label" title="">Gemini:</label>
<textarea id="Gemini-api_key" name="Gemini[api_key]" placeholder="Cookies"></textarea> <textarea id="Gemini-api_key" name="Gemini[api_key]" placeholder="&quot;__Secure-1PSID&quot; cookie"></textarea>
</div> </div>
<div class="field box"> <div class="field box">
<label for="GeminiPro-api_key" class="label" title="">GeminiPro:</label> <label for="GeminiPro-api_key" class="label" title="">GeminiPro:</label>

View File

@ -602,7 +602,8 @@ label[for="camera"] {
width: 100%; width: 100%;
} }
.buttons input:checked+label:after { .buttons input:checked+label:after,
.settings input:checked+label:after {
left: calc(100% - 5px - 20px); left: calc(100% - 5px - 20px);
} }
@ -844,6 +845,10 @@ ul {
max-width: none; max-width: none;
} }
.settings h3 {
padding-left: 50px;
}
.buttons { .buttons {
align-items: flex-start; align-items: flex-start;
flex-wrap: wrap; flex-wrap: wrap;
@ -1099,10 +1104,15 @@ a:-webkit-any-link {
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: auto;
}
.settings h3 {
padding-left: 10px;
padding-top: 10px;
} }
.settings .paper { .settings .paper {
overflow: auto;
flex-direction: column; flex-direction: column;
min-width: 400px; min-width: 400px;
} }

View File

@ -49,6 +49,9 @@ class Api():
else provider.__name__) + else provider.__name__) +
(" (WebDriver)" (" (WebDriver)"
if "webdriver" in provider.get_parameters() if "webdriver" in provider.get_parameters()
else "") +
(" (Auth)"
if provider.needs_auth
else "") else "")
for provider in __providers__ for provider in __providers__
if provider.working if provider.working

View File

@ -6,6 +6,11 @@ try:
has_curl_mime = True has_curl_mime = True
except ImportError: except ImportError:
has_curl_mime = False has_curl_mime = False
try:
from curl_cffi.requests import CurlWsFlag
has_curl_ws = True
except ImportError:
has_curl_ws = False
from typing import AsyncGenerator, Any from typing import AsyncGenerator, Any
from functools import partialmethod from functools import partialmethod
import json import json
@ -73,6 +78,12 @@ class StreamSession(AsyncSession):
"""Create and return a StreamResponse object for the given HTTP request.""" """Create and return a StreamResponse object for the given HTTP request."""
return StreamResponse(super().request(method, url, stream=True, **kwargs)) return StreamResponse(super().request(method, url, stream=True, **kwargs))
def ws_connect(self, url, *args, **kwargs):
return WebSocket(self, url)
def _ws_connect(self, url):
return super().ws_connect(url)
# Defining HTTP methods as partial methods of the request method. # Defining HTTP methods as partial methods of the request method.
head = partialmethod(request, "HEAD") head = partialmethod(request, "HEAD")
get = partialmethod(request, "GET") get = partialmethod(request, "GET")
@ -88,4 +99,25 @@ if has_curl_mime:
else: else:
class FormData(): class FormData():
def __init__(self) -> None: def __init__(self) -> None:
raise RuntimeError("CurlMimi in curl_cffi is missing | pip install -U g4f[curl_cffi]") raise RuntimeError("CurlMimi in curl_cffi is missing | pip install -U g4f[curl_cffi]")
class WebSocket():
def __init__(self, session, url) -> None:
if not has_curl_ws:
raise RuntimeError("CurlWsFlag in curl_cffi is missing | pip install -U g4f[curl_cffi]")
self.session: StreamSession = session
self.url: str = url
async def __aenter__(self):
self.inner = await self.session._ws_connect(self.url)
return self
async def __aexit__(self, *args):
self.inner.aclose()
async def receive_str(self) -> str:
bytes, _ = await self.inner.arecv()
return bytes.decode(errors="ignore")
async def send_str(self, data: str):
await self.inner.asend(data.encode(), CurlWsFlag.TEXT)