Myshell.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. # not using WS anymore
  2. from __future__ import annotations
  3. import json, uuid, hashlib, time, random
  4. from aiohttp import ClientSession
  5. from aiohttp.http import WSMsgType
  6. import asyncio
  7. from ...typing import AsyncResult, Messages
  8. from ..base_provider import AsyncGeneratorProvider, format_prompt
  9. models = {
  10. "samantha": "1e3be7fe89e94a809408b1154a2ee3e1",
  11. "gpt-3.5-turbo": "8077335db7cd47e29f7de486612cc7fd",
  12. "gpt-4": "01c8de4fbfc548df903712b0922a4e01",
  13. }
  14. class Myshell(AsyncGeneratorProvider):
  15. url = "https://app.myshell.ai/chat"
  16. working = False
  17. supports_gpt_35_turbo = True
  18. supports_gpt_4 = True
  19. @classmethod
  20. async def create_async_generator(
  21. cls,
  22. model: str,
  23. messages: Messages,
  24. proxy: str = None,
  25. timeout: int = 90,
  26. **kwargs
  27. ) -> AsyncResult:
  28. if not model:
  29. bot_id = models["samantha"]
  30. elif model in models:
  31. bot_id = models[model]
  32. else:
  33. raise ValueError(f"Model are not supported: {model}")
  34. 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'
  35. visitor_id = generate_visitor_id(user_agent)
  36. async with ClientSession(
  37. headers={'User-Agent': user_agent}
  38. ) as session:
  39. async with session.ws_connect(
  40. "wss://api.myshell.ai/ws/?EIO=4&transport=websocket",
  41. autoping=False,
  42. timeout=timeout,
  43. proxy=proxy
  44. ) as wss:
  45. # Send and receive hello message
  46. await wss.receive_str()
  47. message = json.dumps({"token": None, "visitorId": visitor_id})
  48. await wss.send_str(f"40/chat,{message}")
  49. await wss.receive_str()
  50. # Fix "need_verify_captcha" issue
  51. await asyncio.sleep(5)
  52. # Create chat message
  53. text = format_prompt(messages)
  54. chat_data = json.dumps(["text_chat",{
  55. "reqId": str(uuid.uuid4()),
  56. "botUid": bot_id,
  57. "sourceFrom": "myshellWebsite",
  58. "text": text,
  59. **generate_signature(text)
  60. }])
  61. # Send chat message
  62. chat_start = "42/chat,"
  63. chat_message = f"{chat_start}{chat_data}"
  64. await wss.send_str(chat_message)
  65. # Receive messages
  66. async for message in wss:
  67. if message.type != WSMsgType.TEXT:
  68. continue
  69. # Ping back
  70. if message.data == "2":
  71. await wss.send_str("3")
  72. continue
  73. # Is not chat message
  74. if not message.data.startswith(chat_start):
  75. continue
  76. data_type, data = json.loads(message.data[len(chat_start):])
  77. if data_type == "text_stream":
  78. if data["data"]["text"]:
  79. yield data["data"]["text"]
  80. elif data["data"]["isFinal"]:
  81. break
  82. elif data_type in ("message_replied", "need_verify_captcha"):
  83. raise RuntimeError(f"Received unexpected message: {data_type}")
  84. def generate_timestamp() -> str:
  85. return str(
  86. int(
  87. str(int(time.time() * 1000))[:-1]
  88. + str(
  89. sum(
  90. 2 * int(digit)
  91. if idx % 2 == 0
  92. else 3 * int(digit)
  93. for idx, digit in enumerate(str(int(time.time() * 1000))[:-1])
  94. )
  95. % 10
  96. )
  97. )
  98. )
  99. def generate_signature(text: str):
  100. timestamp = generate_timestamp()
  101. version = 'v1.0.0'
  102. secret = '8@VXGK3kKHr!u2gA'
  103. data = f"{version}#{text}#{timestamp}#{secret}"
  104. signature = hashlib.md5(data.encode()).hexdigest()
  105. signature = signature[::-1]
  106. return {
  107. "signature": signature,
  108. "timestamp": timestamp,
  109. "version": version
  110. }
  111. def xor_hash(B: str):
  112. r = []
  113. i = 0
  114. def o(e, t):
  115. o_val = 0
  116. for i in range(len(t)):
  117. o_val |= r[i] << (8 * i)
  118. return e ^ o_val
  119. for e in range(len(B)):
  120. t = ord(B[e])
  121. r.insert(0, 255 & t)
  122. if len(r) >= 4:
  123. i = o(i, r)
  124. r = []
  125. if len(r) > 0:
  126. i = o(i, r)
  127. return hex(i)[2:]
  128. def performance() -> str:
  129. t = int(time.time() * 1000)
  130. e = 0
  131. while t == int(time.time() * 1000):
  132. e += 1
  133. return hex(t)[2:] + hex(e)[2:]
  134. def generate_visitor_id(user_agent: str) -> str:
  135. f = performance()
  136. r = hex(int(random.random() * (16**16)))[2:-2]
  137. d = xor_hash(user_agent)
  138. e = hex(1080 * 1920)[2:]
  139. return f"{f}-{r}-{d}-{e}-{f}"