mirror of
https://github.com/xtekky/gpt4free.git
synced 2025-12-06 02:30:41 -08:00
* Update model configurations, provider implementations, and documentation - Updated model names and aliases for Qwen QVQ 72B and Qwen 2 72B (@TheFirstNoob) - Revised HuggingSpace class configuration, added default_image_model - Added llama-3.2-70b alias for Llama 3.2 70B model in AutonomousAI - Removed BlackboxCreateAgent class - Added gpt-4o alias for Copilot model - Moved api_key to Mhystical class attribute - Added models property with default_model value for Free2GPT - Simplified Jmuz class implementation - Improved image generation and model handling in DeepInfra - Standardized default models and removed aliases in Gemini - Replaced model aliases with direct model list in GlhfChat (@TheFirstNoob) - Removed trailing slash from image generation URL in PollinationsAI (https://github.com/xtekky/gpt4free/issues/2571) - Updated llama and qwen model configurations - Enhanced provider documentation and model details * Removed from (g4f/models.py) 'Yqcloud' provider from Default due to error 'ResponseStatusError: Response 429: 文字过长,请删减后重试。' * Update docs/providers-and-models.md * refactor(g4f/Provider/DDG.py): Add error handling and rate limiting to DDG provider - Add custom exception classes for rate limits, timeouts, and conversation limits - Implement rate limiting with sleep between requests (0.75s minimum delay) - Add model validation method to check supported models - Add proper error handling for API responses with custom exceptions - Improve session cookie handling for conversation persistence - Clean up User-Agent string and remove redundant code - Add proper error propagation through async generator Breaking changes: - New custom exceptions may require updates to error handling code - Rate limiting affects request timing and throughput - Model validation is now stricter Related: - Adds error handling similar to standard API clients - Improves reliability and robustness of chat interactions * Update g4f/models.py g4f/Provider/PollinationsAI.py * Update g4f/models.py * Restored provider which was not working and was disabled (g4f/Provider/DeepInfraChat.py) * Fixing a bug with Streaming Completions * Update g4f/Provider/PollinationsAI.py * Update g4f/Provider/Blackbox.py g4f/Provider/DDG.py * Added another model for generating images 'ImageGeneration2' to the 'Blackbox' provider * Update docs/providers-and-models.md * Update g4f/models.py g4f/Provider/Blackbox.py * Added a new OIVSCode provider from the Text Models and Vision (Image Upload) model * Update docs/providers-and-models.md * docs: add Conversation Memory class with context handling requested by @TheFirstNoob * Simplified README.md documentation added new docs/configuration.md documentation * Update add README.md docs/configuration.md * Update README.md * Update docs/providers-and-models.md g4f/models.py g4f/Provider/PollinationsAI.py * Added new model deepseek-r1 to Blackbox provider. @TheFirstNoob * Fixed bugs and updated docs/providers-and-models.md etc/unittest/client.py g4f/models.py g4f/Provider/. --------- Co-authored-by: kqlio67 <> Co-authored-by: H Lohaus <hlohaus@users.noreply.github.com>
136 lines
6.1 KiB
Python
136 lines
6.1 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import ssl
|
|
import time
|
|
import uuid
|
|
from pathlib import Path
|
|
|
|
import json
|
|
from aiohttp import ClientSession, TCPConnector, BaseConnector
|
|
from ...requests import raise_for_status
|
|
|
|
from ...typing import AsyncResult, Messages
|
|
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
|
from ...errors import MissingAuthError
|
|
from ..helper import get_connector
|
|
from ...cookies import get_cookies_dir
|
|
|
|
access_token = ""
|
|
token_expires_at = 0
|
|
|
|
RUSSIAN_CA_CERT = """-----BEGIN CERTIFICATE-----
|
|
MIIFwjCCA6qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwcDELMAkGA1UEBhMCUlUx
|
|
PzA9BgNVBAoMNlRoZSBNaW5pc3RyeSBvZiBEaWdpdGFsIERldmVsb3BtZW50IGFu
|
|
ZCBDb21tdW5pY2F0aW9uczEgMB4GA1UEAwwXUnVzc2lhbiBUcnVzdGVkIFJvb3Qg
|
|
Q0EwHhcNMjIwMzAxMjEwNDE1WhcNMzIwMjI3MjEwNDE1WjBwMQswCQYDVQQGEwJS
|
|
VTE/MD0GA1UECgw2VGhlIE1pbmlzdHJ5IG9mIERpZ2l0YWwgRGV2ZWxvcG1lbnQg
|
|
YW5kIENvbW11bmljYXRpb25zMSAwHgYDVQQDDBdSdXNzaWFuIFRydXN0ZWQgUm9v
|
|
dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMfFOZ8pUAL3+r2n
|
|
qqE0Zp52selXsKGFYoG0GM5bwz1bSFtCt+AZQMhkWQheI3poZAToYJu69pHLKS6Q
|
|
XBiwBC1cvzYmUYKMYZC7jE5YhEU2bSL0mX7NaMxMDmH2/NwuOVRj8OImVa5s1F4U
|
|
zn4Kv3PFlDBjjSjXKVY9kmjUBsXQrIHeaqmUIsPIlNWUnimXS0I0abExqkbdrXbX
|
|
YwCOXhOO2pDUx3ckmJlCMUGacUTnylyQW2VsJIyIGA8V0xzdaeUXg0VZ6ZmNUr5Y
|
|
Ber/EAOLPb8NYpsAhJe2mXjMB/J9HNsoFMBFJ0lLOT/+dQvjbdRZoOT8eqJpWnVD
|
|
U+QL/qEZnz57N88OWM3rabJkRNdU/Z7x5SFIM9FrqtN8xewsiBWBI0K6XFuOBOTD
|
|
4V08o4TzJ8+Ccq5XlCUW2L48pZNCYuBDfBh7FxkB7qDgGDiaftEkZZfApRg2E+M9
|
|
G8wkNKTPLDc4wH0FDTijhgxR3Y4PiS1HL2Zhw7bD3CbslmEGgfnnZojNkJtcLeBH
|
|
BLa52/dSwNU4WWLubaYSiAmA9IUMX1/RpfpxOxd4Ykmhz97oFbUaDJFipIggx5sX
|
|
ePAlkTdWnv+RWBxlJwMQ25oEHmRguNYf4Zr/Rxr9cS93Y+mdXIZaBEE0KS2iLRqa
|
|
OiWBki9IMQU4phqPOBAaG7A+eP8PAgMBAAGjZjBkMB0GA1UdDgQWBBTh0YHlzlpf
|
|
BKrS6badZrHF+qwshzAfBgNVHSMEGDAWgBTh0YHlzlpfBKrS6badZrHF+qwshzAS
|
|
BgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
|
|
AAOCAgEAALIY1wkilt/urfEVM5vKzr6utOeDWCUczmWX/RX4ljpRdgF+5fAIS4vH
|
|
tmXkqpSCOVeWUrJV9QvZn6L227ZwuE15cWi8DCDal3Ue90WgAJJZMfTshN4OI8cq
|
|
W9E4EG9wglbEtMnObHlms8F3CHmrw3k6KmUkWGoa+/ENmcVl68u/cMRl1JbW2bM+
|
|
/3A+SAg2c6iPDlehczKx2oa95QW0SkPPWGuNA/CE8CpyANIhu9XFrj3RQ3EqeRcS
|
|
AQQod1RNuHpfETLU/A2gMmvn/w/sx7TB3W5BPs6rprOA37tutPq9u6FTZOcG1Oqj
|
|
C/B7yTqgI7rbyvox7DEXoX7rIiEqyNNUguTk/u3SZ4VXE2kmxdmSh3TQvybfbnXV
|
|
4JbCZVaqiZraqc7oZMnRoWrXRG3ztbnbes/9qhRGI7PqXqeKJBztxRTEVj8ONs1d
|
|
WN5szTwaPIvhkhO3CO5ErU2rVdUr89wKpNXbBODFKRtgxUT70YpmJ46VVaqdAhOZ
|
|
D9EUUn4YaeLaS8AjSF/h7UkjOibNc4qVDiPP+rkehFWM66PVnP1Msh93tc+taIfC
|
|
EYVMxjh8zNbFuoc7fzvvrFILLe7ifvEIUqSVIC/AzplM/Jxw7buXFeGP1qVCBEHq
|
|
391d/9RAfaZ12zkwFsl+IKwE/OZxW8AHa9i1p4GO0YSNuczzEm4=
|
|
-----END CERTIFICATE-----"""
|
|
|
|
class GigaChat(AsyncGeneratorProvider, ProviderModelMixin):
|
|
url = "https://developers.sber.ru/gigachat"
|
|
working = True
|
|
supports_message_history = True
|
|
supports_system_message = True
|
|
supports_stream = True
|
|
needs_auth = True
|
|
default_model = "GigaChat:latest"
|
|
models = [default_model, "GigaChat-Plus", "GigaChat-Pro"]
|
|
|
|
@classmethod
|
|
async def create_async_generator(
|
|
cls,
|
|
model: str,
|
|
messages: Messages,
|
|
stream: bool = True,
|
|
proxy: str = None,
|
|
api_key: str = None,
|
|
connector: BaseConnector = None,
|
|
scope: str = "GIGACHAT_API_PERS",
|
|
update_interval: float = 0,
|
|
**kwargs
|
|
) -> AsyncResult:
|
|
global access_token, token_expires_at
|
|
model = cls.get_model(model)
|
|
if not api_key:
|
|
raise MissingAuthError('Missing "api_key"')
|
|
|
|
# Create certificate file in cookies directory
|
|
cookies_dir = Path(get_cookies_dir())
|
|
cert_file = cookies_dir / 'russian_trusted_root_ca.crt'
|
|
|
|
# Write certificate if it doesn't exist
|
|
if not cert_file.exists():
|
|
cert_file.write_text(RUSSIAN_CA_CERT)
|
|
|
|
ssl_context = ssl.create_default_context(cafile=str(cert_file))
|
|
if connector is None:
|
|
connector = TCPConnector(ssl_context=ssl_context)
|
|
|
|
async with ClientSession(connector=get_connector(connector, proxy)) as session:
|
|
if token_expires_at - int(time.time() * 1000) < 60000:
|
|
async with session.post(url="https://ngw.devices.sberbank.ru:9443/api/v2/oauth",
|
|
headers={"Authorization": f"Bearer {api_key}",
|
|
"RqUID": str(uuid.uuid4()),
|
|
"Content-Type": "application/x-www-form-urlencoded"},
|
|
data={"scope": scope}) as response:
|
|
await raise_for_status(response)
|
|
data = await response.json()
|
|
access_token = data['access_token']
|
|
token_expires_at = data['expires_at']
|
|
|
|
async with session.post(url="https://gigachat.devices.sberbank.ru/api/v1/chat/completions",
|
|
headers={"Authorization": f"Bearer {access_token}"},
|
|
json={
|
|
"model": model,
|
|
"messages": messages,
|
|
"stream": stream,
|
|
"update_interval": update_interval,
|
|
**kwargs
|
|
}) as response:
|
|
await raise_for_status(response)
|
|
|
|
async for line in response.content:
|
|
if not stream:
|
|
yield json.loads(line.decode("utf-8"))['choices'][0]['message']['content']
|
|
return
|
|
|
|
if line and line.startswith(b"data:"):
|
|
line = line[6:-1] # remove "data: " prefix and "\n" suffix
|
|
if line.strip() == b"[DONE]":
|
|
return
|
|
else:
|
|
msg = json.loads(line.decode("utf-8"))['choices'][0]
|
|
content = msg['delta']['content']
|
|
|
|
if content:
|
|
yield content
|
|
|
|
if 'finish_reason' in msg:
|
|
return
|