GigaChat.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. from __future__ import annotations
  2. import os
  3. try:
  4. import ssl
  5. has_ssl = True
  6. except ImportError:
  7. has_ssl = False
  8. import time
  9. import uuid
  10. from pathlib import Path
  11. import json
  12. from aiohttp import ClientSession, TCPConnector, BaseConnector
  13. from ...requests import raise_for_status
  14. from ...typing import AsyncResult, Messages
  15. from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
  16. from ...errors import MissingAuthError
  17. from ..helper import get_connector
  18. from ...cookies import get_cookies_dir
  19. access_token = ""
  20. token_expires_at = 0
  21. RUSSIAN_CA_CERT = """-----BEGIN CERTIFICATE-----
  22. MIIFwjCCA6qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwcDELMAkGA1UEBhMCUlUx
  23. PzA9BgNVBAoMNlRoZSBNaW5pc3RyeSBvZiBEaWdpdGFsIERldmVsb3BtZW50IGFu
  24. ZCBDb21tdW5pY2F0aW9uczEgMB4GA1UEAwwXUnVzc2lhbiBUcnVzdGVkIFJvb3Qg
  25. Q0EwHhcNMjIwMzAxMjEwNDE1WhcNMzIwMjI3MjEwNDE1WjBwMQswCQYDVQQGEwJS
  26. VTE/MD0GA1UECgw2VGhlIE1pbmlzdHJ5IG9mIERpZ2l0YWwgRGV2ZWxvcG1lbnQg
  27. YW5kIENvbW11bmljYXRpb25zMSAwHgYDVQQDDBdSdXNzaWFuIFRydXN0ZWQgUm9v
  28. dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMfFOZ8pUAL3+r2n
  29. qqE0Zp52selXsKGFYoG0GM5bwz1bSFtCt+AZQMhkWQheI3poZAToYJu69pHLKS6Q
  30. XBiwBC1cvzYmUYKMYZC7jE5YhEU2bSL0mX7NaMxMDmH2/NwuOVRj8OImVa5s1F4U
  31. zn4Kv3PFlDBjjSjXKVY9kmjUBsXQrIHeaqmUIsPIlNWUnimXS0I0abExqkbdrXbX
  32. YwCOXhOO2pDUx3ckmJlCMUGacUTnylyQW2VsJIyIGA8V0xzdaeUXg0VZ6ZmNUr5Y
  33. Ber/EAOLPb8NYpsAhJe2mXjMB/J9HNsoFMBFJ0lLOT/+dQvjbdRZoOT8eqJpWnVD
  34. U+QL/qEZnz57N88OWM3rabJkRNdU/Z7x5SFIM9FrqtN8xewsiBWBI0K6XFuOBOTD
  35. 4V08o4TzJ8+Ccq5XlCUW2L48pZNCYuBDfBh7FxkB7qDgGDiaftEkZZfApRg2E+M9
  36. G8wkNKTPLDc4wH0FDTijhgxR3Y4PiS1HL2Zhw7bD3CbslmEGgfnnZojNkJtcLeBH
  37. BLa52/dSwNU4WWLubaYSiAmA9IUMX1/RpfpxOxd4Ykmhz97oFbUaDJFipIggx5sX
  38. ePAlkTdWnv+RWBxlJwMQ25oEHmRguNYf4Zr/Rxr9cS93Y+mdXIZaBEE0KS2iLRqa
  39. OiWBki9IMQU4phqPOBAaG7A+eP8PAgMBAAGjZjBkMB0GA1UdDgQWBBTh0YHlzlpf
  40. BKrS6badZrHF+qwshzAfBgNVHSMEGDAWgBTh0YHlzlpfBKrS6badZrHF+qwshzAS
  41. BgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
  42. AAOCAgEAALIY1wkilt/urfEVM5vKzr6utOeDWCUczmWX/RX4ljpRdgF+5fAIS4vH
  43. tmXkqpSCOVeWUrJV9QvZn6L227ZwuE15cWi8DCDal3Ue90WgAJJZMfTshN4OI8cq
  44. W9E4EG9wglbEtMnObHlms8F3CHmrw3k6KmUkWGoa+/ENmcVl68u/cMRl1JbW2bM+
  45. /3A+SAg2c6iPDlehczKx2oa95QW0SkPPWGuNA/CE8CpyANIhu9XFrj3RQ3EqeRcS
  46. AQQod1RNuHpfETLU/A2gMmvn/w/sx7TB3W5BPs6rprOA37tutPq9u6FTZOcG1Oqj
  47. C/B7yTqgI7rbyvox7DEXoX7rIiEqyNNUguTk/u3SZ4VXE2kmxdmSh3TQvybfbnXV
  48. 4JbCZVaqiZraqc7oZMnRoWrXRG3ztbnbes/9qhRGI7PqXqeKJBztxRTEVj8ONs1d
  49. WN5szTwaPIvhkhO3CO5ErU2rVdUr89wKpNXbBODFKRtgxUT70YpmJ46VVaqdAhOZ
  50. D9EUUn4YaeLaS8AjSF/h7UkjOibNc4qVDiPP+rkehFWM66PVnP1Msh93tc+taIfC
  51. EYVMxjh8zNbFuoc7fzvvrFILLe7ifvEIUqSVIC/AzplM/Jxw7buXFeGP1qVCBEHq
  52. 391d/9RAfaZ12zkwFsl+IKwE/OZxW8AHa9i1p4GO0YSNuczzEm4=
  53. -----END CERTIFICATE-----"""
  54. class GigaChat(AsyncGeneratorProvider, ProviderModelMixin):
  55. url = "https://developers.sber.ru/gigachat"
  56. working = True
  57. supports_message_history = True
  58. supports_system_message = True
  59. supports_stream = True
  60. needs_auth = True
  61. default_model = "GigaChat:latest"
  62. models = [default_model, "GigaChat-Plus", "GigaChat-Pro"]
  63. @classmethod
  64. async def create_async_generator(
  65. cls,
  66. model: str,
  67. messages: Messages,
  68. stream: bool = True,
  69. proxy: str = None,
  70. api_key: str = None,
  71. connector: BaseConnector = None,
  72. scope: str = "GIGACHAT_API_PERS",
  73. update_interval: float = 0,
  74. **kwargs
  75. ) -> AsyncResult:
  76. global access_token, token_expires_at
  77. model = cls.get_model(model)
  78. if not api_key:
  79. raise MissingAuthError('Missing "api_key"')
  80. # Create certificate file in cookies directory
  81. cookies_dir = Path(get_cookies_dir())
  82. cert_file = cookies_dir / 'russian_trusted_root_ca.crt'
  83. # Write certificate if it doesn't exist
  84. if not cert_file.exists():
  85. cert_file.write_text(RUSSIAN_CA_CERT)
  86. if has_ssl and connector is None:
  87. ssl_context = ssl.create_default_context(cafile=str(cert_file))
  88. connector = TCPConnector(ssl_context=ssl_context)
  89. async with ClientSession(connector=get_connector(connector, proxy)) as session:
  90. if token_expires_at - int(time.time() * 1000) < 60000:
  91. async with session.post(url="https://ngw.devices.sberbank.ru:9443/api/v2/oauth",
  92. headers={"Authorization": f"Bearer {api_key}",
  93. "RqUID": str(uuid.uuid4()),
  94. "Content-Type": "application/x-www-form-urlencoded"},
  95. data={"scope": scope}) as response:
  96. await raise_for_status(response)
  97. data = await response.json()
  98. access_token = data['access_token']
  99. token_expires_at = data['expires_at']
  100. async with session.post(url="https://gigachat.devices.sberbank.ru/api/v1/chat/completions",
  101. headers={"Authorization": f"Bearer {access_token}"},
  102. json={
  103. "model": model,
  104. "messages": messages,
  105. "stream": stream,
  106. "update_interval": update_interval,
  107. **kwargs
  108. }) as response:
  109. await raise_for_status(response)
  110. async for line in response.content:
  111. if not stream:
  112. yield json.loads(line.decode("utf-8"))['choices'][0]['message']['content']
  113. return
  114. if line and line.startswith(b"data:"):
  115. line = line[6:-1] # remove "data: " prefix and "\n" suffix
  116. if line.strip() == b"[DONE]":
  117. return
  118. else:
  119. msg = json.loads(line.decode("utf-8"))['choices'][0]
  120. content = msg['delta']['content']
  121. if content:
  122. yield content
  123. if 'finish_reason' in msg:
  124. return