You.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. from __future__ import annotations
  2. import re
  3. import json
  4. import uuid
  5. from ..typing import AsyncResult, Messages, ImageType, Cookies
  6. from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
  7. from .helper import format_prompt
  8. from ..image import ImageResponse, ImagePreview, EXTENSIONS_MAP, to_bytes, is_accepted_format
  9. from ..requests import StreamSession, FormData, raise_for_status, get_nodriver
  10. from ..cookies import get_cookies
  11. from ..errors import MissingRequirementsError
  12. from .. import debug
  13. class You(AsyncGeneratorProvider, ProviderModelMixin):
  14. label = "You.com"
  15. url = "https://you.com"
  16. working = True
  17. default_model = "gpt-4o-mini"
  18. default_vision_model = "agent"
  19. image_models = ["dall-e"]
  20. models = [
  21. default_model,
  22. "gpt-4o",
  23. "gpt-4-turbo",
  24. "gpt-4",
  25. "claude-3.5-sonnet",
  26. "claude-3-opus",
  27. "claude-3-sonnet",
  28. "claude-3-haiku",
  29. "claude-2",
  30. "llama-3.1-70b",
  31. "llama-3",
  32. "gemini-1-5-flash",
  33. "gemini-1-5-pro",
  34. "gemini-1-0-pro",
  35. "databricks-dbrx-instruct",
  36. "command-r",
  37. "command-r-plus",
  38. "dolphin-2.5",
  39. default_vision_model,
  40. *image_models
  41. ]
  42. _cookies = None
  43. _cookies_used = 0
  44. _telemetry_ids = []
  45. @classmethod
  46. async def create_async_generator(
  47. cls,
  48. model: str,
  49. messages: Messages,
  50. stream: bool = True,
  51. image: ImageType = None,
  52. image_name: str = None,
  53. proxy: str = None,
  54. timeout: int = 240,
  55. chat_mode: str = "default",
  56. cookies: Cookies = None,
  57. **kwargs,
  58. ) -> AsyncResult:
  59. if image is not None or model == cls.default_vision_model:
  60. chat_mode = "agent"
  61. elif not model or model == cls.default_model:
  62. ...
  63. elif model.startswith("dall-e"):
  64. chat_mode = "create"
  65. messages = [messages[-1]]
  66. else:
  67. chat_mode = "custom"
  68. model = cls.get_model(model)
  69. if cookies is None and chat_mode != "default":
  70. try:
  71. cookies = get_cookies(".you.com")
  72. except MissingRequirementsError:
  73. browser = await get_nodriver(proxy=proxy)
  74. page = await browser.get(cls.url)
  75. await page.wait_for('[data-testid="user-profile-button"]', timeout=900)
  76. cookies = {}
  77. for c in await page.send(nodriver.cdp.network.get_cookies([cls.url])):
  78. cookies[c.name] = c.value
  79. await page.close()
  80. async with StreamSession(
  81. proxy=proxy,
  82. impersonate="chrome",
  83. timeout=(30, timeout)
  84. ) as session:
  85. upload = ""
  86. if image is not None:
  87. upload_file = await cls.upload_file(
  88. session, cookies,
  89. to_bytes(image), image_name
  90. )
  91. upload = json.dumps([upload_file])
  92. headers = {
  93. "Accept": "text/event-stream",
  94. "Referer": f"{cls.url}/search?fromSearchBar=true&tbm=youchat",
  95. }
  96. data = {
  97. "userFiles": upload,
  98. "q": format_prompt(messages),
  99. "domain": "youchat",
  100. "selectedChatMode": chat_mode,
  101. "conversationTurnId": str(uuid.uuid4()),
  102. "chatId": str(uuid.uuid4()),
  103. }
  104. params = {
  105. "userFiles": upload,
  106. "selectedChatMode": chat_mode,
  107. }
  108. if chat_mode == "custom":
  109. if debug.logging:
  110. print(f"You model: {model}")
  111. params["selectedAiModel"] = model.replace("-", "_")
  112. async with (session.post if chat_mode == "default" else session.get)(
  113. f"{cls.url}/api/streamingSearch",
  114. data=data if chat_mode == "default" else None,
  115. params=params if chat_mode == "default" else data,
  116. headers=headers,
  117. cookies=cookies
  118. ) as response:
  119. await raise_for_status(response)
  120. async for line in response.iter_lines():
  121. if line.startswith(b'event: '):
  122. event = line[7:].decode()
  123. elif line.startswith(b'data: '):
  124. if event in ["youChatUpdate", "youChatToken"]:
  125. data = json.loads(line[6:])
  126. if event == "youChatToken" and event in data and data[event]:
  127. yield data[event]
  128. elif event == "youChatUpdate" and "t" in data and data["t"]:
  129. if chat_mode == "create":
  130. match = re.search(r"!\[(.+?)\]\((.+?)\)", data["t"])
  131. if match:
  132. if match.group(1) == "fig":
  133. yield ImagePreview(match.group(2), messages[-1]["content"])
  134. else:
  135. yield ImageResponse(match.group(2), match.group(1))
  136. else:
  137. yield data["t"]
  138. else:
  139. yield data["t"]
  140. @classmethod
  141. async def upload_file(cls, client: StreamSession, cookies: Cookies, file: bytes, filename: str = None) -> dict:
  142. async with client.get(
  143. f"{cls.url}/api/get_nonce",
  144. cookies=cookies,
  145. ) as response:
  146. await raise_for_status(response)
  147. upload_nonce = await response.text()
  148. data = FormData()
  149. content_type = is_accepted_format(file)
  150. filename = f"image.{EXTENSIONS_MAP[content_type]}" if filename is None else filename
  151. data.add_field('file', file, content_type=content_type, filename=filename)
  152. async with client.post(
  153. f"{cls.url}/api/upload",
  154. data=data,
  155. headers={
  156. "X-Upload-Nonce": upload_nonce,
  157. },
  158. cookies=cookies
  159. ) as response:
  160. await raise_for_status(response)
  161. result = await response.json()
  162. result["user_filename"] = filename
  163. result["size"] = len(file)
  164. return result