Add upload image support in You

This commit is contained in:
Heiner Lohaus 2024-02-11 07:48:07 +01:00
parent 331826b003
commit 98c7b5ed68

View file

@ -3,67 +3,114 @@ from __future__ import annotations
import json import json
import base64 import base64
import uuid import uuid
from aiohttp import ClientSession, FormData
from ..requests import StreamSession from ..typing import AsyncGenerator, Messages, ImageType, Cookies
from ..typing import AsyncGenerator, Messages from .base_provider import AsyncGeneratorProvider
from .base_provider import AsyncGeneratorProvider, format_prompt from .helper import get_connector, format_prompt
from ..image import to_bytes
from ..defaults import DEFAULT_HEADERS
class You(AsyncGeneratorProvider): class You(AsyncGeneratorProvider):
url = "https://you.com" url = "https://you.com"
working = True working = True
supports_gpt_35_turbo = True supports_gpt_35_turbo = True
supports_gpt_4 = True supports_gpt_4 = True
_session_used = 0 _cookies = None
_session_token = None _cookies_used = 0
@classmethod @classmethod
async def create_async_generator( async def create_async_generator(
cls, cls,
model: str, model: str,
messages: Messages, messages: Messages,
image: ImageType = None,
image_name: str = None,
proxy: str = None, proxy: str = None,
timeout: int = 120, chat_mode: str = "default",
**kwargs, **kwargs,
) -> AsyncGenerator: ) -> AsyncGenerator:
async with StreamSession(proxies={"https": proxy}, impersonate="chrome107", timeout=timeout) as session: async with ClientSession(
connector=get_connector(kwargs.get("connector"), proxy),
headers=DEFAULT_HEADERS
) as client:
if image:
chat_mode = "agent"
elif model == "gpt-4":
chat_mode = model
cookies = await cls.get_cookies(client) if chat_mode != "default" else None
upload = json.dumps([await cls.upload_file(client, cookies, to_bytes(image), image_name)]) if image else ""
#questions = [message["content"] for message in messages if message["role"] == "user"]
# chat = [
# {"question": questions[idx-1], "answer": message["content"]}
# for idx, message in enumerate(messages)
# if message["role"] == "assistant"
# and idx < len(questions)
# ]
headers = { headers = {
"Accept": "text/event-stream", "Accept": "text/event-stream",
"Referer": f"{cls.url}/search?fromSearchBar=true&tbm=youchat", "Referer": f"{cls.url}/search?fromSearchBar=true&tbm=youchat",
} }
data = { data = {
"userFiles": upload,
"selectedChatMode": chat_mode,
"q": format_prompt(messages), "q": format_prompt(messages),
"domain": "youchat", "domain": "youchat",
"chat": "", "selectedChatMode": "gpt-4" if model == "gpt-4" else "default" #"chat": json.dumps(chat),
} }
async with session.get( async with client.post(
f"{cls.url}/api/streamingSearch", f"{cls.url}/api/streamingSearch",
params=data, data=data,
headers=headers, headers=headers,
cookies=cls.get_cookies(await cls.get_session_token(proxy, timeout)) if model == "gpt-4" else None cookies=cookies
) as response: ) as response:
response.raise_for_status() response.raise_for_status()
start = b'data: {"youChatToken": ' async for line in response.content:
async for line in response.iter_lines(): if line.startswith(b'event: '):
if line.startswith(start): event = line[7:-1]
yield json.loads(line[len(start):-1]) elif line.startswith(b'data: '):
if event == b"youChatUpdate" or event == b"youChatToken":
data = json.loads(line[6:-1])
if event == b"youChatToken" and "youChatToken" in data:
yield data["youChatToken"]
elif event == b"youChatUpdate" and "t" in data:
yield data["t"]
@classmethod @classmethod
async def get_session_token(cls, proxy: str, timeout: int): async def upload_file(cls, client: ClientSession, cookies: Cookies, file: bytes, filename: str = None) -> dict:
if not cls._session_token or cls._session_used >= 5: async with client.get(
cls._session_token = await cls.create_session_token(proxy, timeout) f"{cls.url}/api/get_nonce",
cls._session_used += 1 cookies=cookies,
return cls._session_token ) as response:
response.raise_for_status()
def get_cookies(access_token: str, session_jwt: str = "0"): upload_nonce = await response.text()
return { data = FormData()
'stytch_session_jwt': session_jwt, data.add_field('file', file, filename=filename)
'ydc_stytch_session': access_token, async with client.post(
'ydc_stytch_session_jwt': session_jwt f"{cls.url}/api/upload",
} data=data,
headers={
"X-Upload-Nonce": upload_nonce,
},
cookies=cookies
) as response:
if not response.ok:
raise RuntimeError(f"Response: {await response.text()}")
result = await response.json()
result["user_filename"] = filename
result["size"] = len(file)
return result
@classmethod @classmethod
def get_jwt(cls): async def get_cookies(cls, client: ClientSession) -> Cookies:
if not cls._cookies or cls._cookies_used >= 5:
cls._cookies = await cls.create_cookies(client)
cls._cookies_used = 0
cls._cookies_used += 1
return cls._cookies
@classmethod
def get_sdk(cls) -> str:
return base64.standard_b64encode(json.dumps({ return base64.standard_b64encode(json.dumps({
"event_id":f"event-id-{str(uuid.uuid4())}", "event_id":f"event-id-{str(uuid.uuid4())}",
"app_session_id":f"app-session-id-{str(uuid.uuid4())}", "app_session_id":f"app-session-id-{str(uuid.uuid4())}",
@ -75,26 +122,34 @@ class You(AsyncGeneratorProvider):
"sdk":{"identifier":"Stytch.js Javascript SDK","version":"3.3.0" "sdk":{"identifier":"Stytch.js Javascript SDK","version":"3.3.0"
}}).encode()).decode() }}).encode()).decode()
def get_auth() -> str:
auth_uuid = "507a52ad-7e69-496b-aee0-1c9863c7c8"
auth_token = f"public-token-live-{auth_uuid}bb:public-token-live-{auth_uuid}19"
auth = base64.standard_b64encode(auth_token.encode()).decode()
return f"Basic {auth}",
@classmethod @classmethod
async def create_session_token(cls, proxy: str, timeout: int): async def create_cookies(cls, client: ClientSession) -> Cookies:
async with StreamSession(proxies={"https": proxy}, impersonate="chrome110", timeout=timeout) as session: user_uuid = str(uuid.uuid4())
user_uuid = str(uuid.uuid4()) async with client.post(
auth_uuid = "507a52ad-7e69-496b-aee0-1c9863c7c8" "https://web.stytch.com/sdk/v1/passwords",
auth_token = f"public-token-live-{auth_uuid}bb:public-token-live-{auth_uuid}19" headers={
auth = base64.standard_b64encode(auth_token.encode()).decode() "Authorization": cls.get_auth(),
async with session.post( "X-SDK-Client": cls.get_sdk(),
"https://web.stytch.com/sdk/v1/passwords", "X-SDK-Parent-Host": cls.url
headers={ },
"Authorization": f"Basic {auth}", json={
"X-SDK-Client": cls.get_jwt(), "email": f"{user_uuid}@gmail.com",
"X-SDK-Parent-Host": "https://you.com" "password": f"{user_uuid}#{user_uuid}",
}, "session_duration_minutes": 129600
json={ }
"email": f"{user_uuid}@gmail.com", ) as response:
"password": f"{user_uuid}#{user_uuid}", if not response.ok:
"session_duration_minutes": 129600 raise RuntimeError(f"Response: {await response.text()}")
} session = (await response.json())["data"]
) as response: return {
if not response.ok: "stytch_session": session["session_token"],
raise RuntimeError(f"Response: {await response.text()}") 'stytch_session_jwt': session["session_jwt"],
return (await response.json())["data"]["session_token"] 'ydc_stytch_session': session["session_token"],
'ydc_stytch_session_jwt': session["session_jwt"],
}