mirror of
https://github.com/xtekky/gpt4free.git
synced 2024-12-25 04:01:52 +03:00
6ce493d4df
* Fix api streaming, fix AsyncClient, Improve Client class, Some providers fixes, Update models list, Fix some tests, Update model list in Airforce provid er, Add OpenAi image generation url to api, Fix reload and debug in api arguments, Fix websearch in gui * Fix Cloadflare and Pi and AmigoChat provider * Fix conversation support in DDG provider, Add cloudflare bypass with nodriver * Fix unittests without curl_cffi
171 lines
5.9 KiB
Python
171 lines
5.9 KiB
Python
from __future__ import annotations
|
|
|
|
import random
|
|
import json
|
|
import re
|
|
|
|
from ..typing import AsyncResult, Messages
|
|
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
|
|
from ..image import ImageResponse
|
|
from ..requests import StreamSession, raise_for_status
|
|
from .airforce.AirforceChat import AirforceChat
|
|
from .airforce.AirforceImage import AirforceImage
|
|
|
|
class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
|
|
url = "https://api.airforce"
|
|
api_endpoint_completions = AirforceChat.api_endpoint
|
|
api_endpoint_imagine = AirforceImage.api_endpoint
|
|
working = True
|
|
default_model = "gpt-4o-mini"
|
|
supports_system_message = True
|
|
supports_message_history = True
|
|
text_models = [
|
|
'gpt-4-turbo',
|
|
default_model,
|
|
'llama-3.1-70b-turbo',
|
|
'llama-3.1-8b-turbo',
|
|
]
|
|
image_models = [
|
|
'flux',
|
|
'flux-realism',
|
|
'flux-anime',
|
|
'flux-3d',
|
|
'flux-disney',
|
|
'flux-pixel',
|
|
'flux-4o',
|
|
'any-dark',
|
|
]
|
|
models = [
|
|
*text_models,
|
|
*image_models,
|
|
]
|
|
model_aliases = {
|
|
"gpt-4o": "chatgpt-4o-latest",
|
|
"llama-3.1-70b": "llama-3.1-70b-turbo",
|
|
"llama-3.1-8b": "llama-3.1-8b-turbo",
|
|
"gpt-4": "gpt-4-turbo",
|
|
}
|
|
|
|
@classmethod
|
|
def create_async_generator(
|
|
cls,
|
|
model: str,
|
|
messages: Messages,
|
|
proxy: str = None,
|
|
seed: int = None,
|
|
size: str = "1:1",
|
|
stream: bool = False,
|
|
**kwargs
|
|
) -> AsyncResult:
|
|
model = cls.get_model(model)
|
|
|
|
if model in cls.image_models:
|
|
return cls._generate_image(model, messages, proxy, seed, size)
|
|
else:
|
|
return cls._generate_text(model, messages, proxy, stream, **kwargs)
|
|
|
|
@classmethod
|
|
async def _generate_image(
|
|
cls,
|
|
model: str,
|
|
messages: Messages,
|
|
proxy: str = None,
|
|
seed: int = None,
|
|
size: str = "1:1",
|
|
**kwargs
|
|
) -> AsyncResult:
|
|
headers = {
|
|
"accept": "*/*",
|
|
"accept-language": "en-US,en;q=0.9",
|
|
"cache-control": "no-cache",
|
|
"origin": "https://llmplayground.net",
|
|
"user-agent": "Mozilla/5.0"
|
|
}
|
|
if seed is None:
|
|
seed = random.randint(0, 100000)
|
|
prompt = messages[-1]['content']
|
|
|
|
async with StreamSession(headers=headers, proxy=proxy) as session:
|
|
params = {
|
|
"model": model,
|
|
"prompt": prompt,
|
|
"size": size,
|
|
"seed": seed
|
|
}
|
|
async with session.get(f"{cls.api_endpoint_imagine}", params=params) as response:
|
|
await raise_for_status(response)
|
|
content_type = response.headers.get('Content-Type', '').lower()
|
|
|
|
if 'application/json' in content_type:
|
|
raise RuntimeError(await response.json().get("error", {}).get("message"))
|
|
elif 'image' in content_type:
|
|
image_data = b""
|
|
async for chunk in response.iter_content():
|
|
if chunk:
|
|
image_data += chunk
|
|
image_url = f"{cls.api_endpoint_imagine}?model={model}&prompt={prompt}&size={size}&seed={seed}"
|
|
yield ImageResponse(images=image_url, alt=prompt)
|
|
|
|
@classmethod
|
|
async def _generate_text(
|
|
cls,
|
|
model: str,
|
|
messages: Messages,
|
|
proxy: str = None,
|
|
stream: bool = False,
|
|
max_tokens: int = 4096,
|
|
temperature: float = 1,
|
|
top_p: float = 1,
|
|
**kwargs
|
|
) -> AsyncResult:
|
|
headers = {
|
|
"accept": "*/*",
|
|
"accept-language": "en-US,en;q=0.9",
|
|
"authorization": "Bearer missing api key",
|
|
"content-type": "application/json",
|
|
"user-agent": "Mozilla/5.0"
|
|
}
|
|
async with StreamSession(headers=headers, proxy=proxy) as session:
|
|
data = {
|
|
"messages": messages,
|
|
"model": model,
|
|
"max_tokens": max_tokens,
|
|
"temperature": temperature,
|
|
"top_p": top_p,
|
|
"stream": stream
|
|
}
|
|
async with session.post(cls.api_endpoint_completions, json=data) as response:
|
|
await raise_for_status(response)
|
|
content_type = response.headers.get('Content-Type', '').lower()
|
|
if 'application/json' in content_type:
|
|
json_data = await response.json()
|
|
if json_data.get("model") == "error":
|
|
raise RuntimeError(json_data['choices'][0]['message'].get('content', ''))
|
|
if stream:
|
|
async for line in response.iter_lines():
|
|
if line:
|
|
line = line.decode('utf-8').strip()
|
|
if line.startswith("data: ") and line != "data: [DONE]":
|
|
json_data = json.loads(line[6:])
|
|
content = json_data['choices'][0]['delta'].get('content', '')
|
|
if content:
|
|
yield cls._filter_content(content)
|
|
else:
|
|
json_data = await response.json()
|
|
content = json_data['choices'][0]['message']['content']
|
|
yield cls._filter_content(content)
|
|
|
|
@classmethod
|
|
def _filter_content(cls, part_response: str) -> str:
|
|
part_response = re.sub(
|
|
r"One message exceeds the \d+chars per message limit\..+https:\/\/discord\.com\/invite\/\S+",
|
|
'',
|
|
part_response
|
|
)
|
|
|
|
part_response = re.sub(
|
|
r"Rate limit \(\d+\/minute\) exceeded\. Join our discord for more: .+https:\/\/discord\.com\/invite\/\S+",
|
|
'',
|
|
part_response
|
|
)
|
|
return part_response |