gpt4free/g4f/Provider/not_working/Airforce.py
kqlio67 9def1aa71f
Update model configurations, provider implementations, and documentation (#2577)
* 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>
2025-01-24 03:47:57 +01:00

276 lines
11 KiB
Python

import json
import random
import re
import requests
from aiohttp import ClientSession
from typing import List
from ...typing import AsyncResult, Messages
from ...image import ImageResponse
from ...providers.response import FinishReason, Usage
from ...requests.raise_for_status import raise_for_status
from ..base_provider import AsyncGeneratorProvider, ProviderModelMixin
from ... import debug
def split_message(message: str, max_length: int = 1000) -> List[str]:
"""Splits the message into parts up to (max_length)."""
chunks = []
while len(message) > max_length:
split_point = message.rfind(' ', 0, max_length)
if split_point == -1:
split_point = max_length
chunks.append(message[:split_point])
message = message[split_point:].strip()
if message:
chunks.append(message)
return chunks
class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
url = "https://api.airforce"
api_endpoint_completions = "https://api.airforce/chat/completions"
api_endpoint_imagine2 = "https://api.airforce/imagine2"
working = False
supports_stream = True
supports_system_message = True
supports_message_history = True
default_model = "llama-3.1-70b-chat"
default_image_model = "flux"
models = []
image_models = []
hidden_models = {"Flux-1.1-Pro"}
additional_models_imagine = ["flux-1.1-pro", "midjourney", "dall-e-3"]
model_aliases = {
# Alias mappings for models
"openchat-3.5": "openchat-3.5-0106",
"deepseek-coder": "deepseek-coder-6.7b-instruct",
"hermes-2-dpo": "Nous-Hermes-2-Mixtral-8x7B-DPO",
"hermes-2-pro": "hermes-2-pro-mistral-7b",
"openhermes-2.5": "openhermes-2.5-mistral-7b",
"lfm-40b": "lfm-40b-moe",
"german-7b": "discolm-german-7b-v1",
"llama-2-7b": "llama-2-7b-chat-int8",
"llama-3.1-70b": "llama-3.1-70b-chat",
"llama-3.1-8b": "llama-3.1-8b-chat",
"llama-3.1-70b": "llama-3.1-70b-turbo",
"llama-3.1-8b": "llama-3.1-8b-turbo",
"neural-7b": "neural-chat-7b-v3-1",
"zephyr-7b": "zephyr-7b-beta",
"evil": "any-uncensored",
"sdxl": "stable-diffusion-xl-lightning",
"sdxl": "stable-diffusion-xl-base",
"flux-pro": "flux-1.1-pro",
"llama-3.1-8b": "llama-3.1-8b-chat"
}
@classmethod
def get_models(cls):
"""Get available models with error handling"""
if not cls.image_models:
try:
response = requests.get(
f"{cls.url}/imagine2/models",
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
}
)
response.raise_for_status()
cls.image_models = response.json()
if isinstance(cls.image_models, list):
cls.image_models.extend(cls.additional_models_imagine)
else:
cls.image_models = cls.additional_models_imagine.copy()
except Exception as e:
debug.log(f"Error fetching image models: {e}")
cls.image_models = cls.additional_models_imagine.copy()
if not cls.models:
try:
response = requests.get(
f"{cls.url}/models",
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
}
)
response.raise_for_status()
data = response.json()
if isinstance(data, dict) and 'data' in data:
cls.models = [model['id'] for model in data['data']]
cls.models.extend(cls.image_models)
cls.models = [model for model in cls.models if model not in cls.hidden_models]
else:
cls.models = list(cls.model_aliases.keys())
except Exception as e:
debug.log(f"Error fetching text models: {e}")
cls.models = list(cls.model_aliases.keys())
return cls.models or list(cls.model_aliases.keys())
@classmethod
def get_model(cls, model: str) -> str:
"""Get the actual model name from alias"""
return cls.model_aliases.get(model, model or cls.default_model)
@classmethod
def _filter_content(cls, part_response: str) -> str:
"""
Filters out unwanted content from the partial response.
"""
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
@classmethod
def _filter_response(cls, response: str) -> str:
"""
Filters the full response to remove system errors and other unwanted text.
"""
if "Model not found or too long input. Or any other error (xD)" in response:
raise ValueError(response)
filtered_response = re.sub(r"\[ERROR\] '\w{8}-\w{4}-\w{4}-\w{4}-\w{12}'", '', response) # any-uncensored
filtered_response = re.sub(r'<\|im_end\|>', '', filtered_response) # remove <|im_end|> token
filtered_response = re.sub(r'</s>', '', filtered_response) # neural-chat-7b-v3-1
filtered_response = re.sub(r'^(Assistant: |AI: |ANSWER: |Output: )', '', filtered_response) # phi-2
filtered_response = cls._filter_content(filtered_response)
return filtered_response
@classmethod
async def generate_image(
cls,
model: str,
prompt: str,
size: str,
seed: int,
proxy: str = None
) -> AsyncResult:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0",
"Accept": "image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Content-Type": "application/json",
}
params = {"model": model, "prompt": prompt, "size": size, "seed": seed}
async with ClientSession(headers=headers) as session:
async with session.get(cls.api_endpoint_imagine2, params=params, proxy=proxy) as response:
if response.status == 200:
image_url = str(response.url)
yield ImageResponse(images=image_url, alt=prompt)
else:
error_text = await response.text()
raise RuntimeError(f"Image generation failed: {response.status} - {error_text}")
@classmethod
async def generate_text(
cls,
model: str,
messages: Messages,
max_tokens: int,
temperature: float,
top_p: float,
stream: bool,
proxy: str = None
) -> AsyncResult:
"""
Generates text, buffers the response, filters it, and returns the final result.
"""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0",
"Accept": "application/json, text/event-stream",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate, br",
"Content-Type": "application/json",
}
final_messages = []
for message in messages:
message_chunks = split_message(message["content"], max_length=1000)
final_messages.extend([{"role": message["role"], "content": chunk} for chunk in message_chunks])
data = {
"messages": final_messages,
"model": model,
"temperature": temperature,
"top_p": top_p,
"stream": stream,
}
if max_tokens != 512:
data["max_tokens"] = max_tokens
async with ClientSession(headers=headers) as session:
async with session.post(cls.api_endpoint_completions, json=data, proxy=proxy) as response:
await raise_for_status(response)
if stream:
idx = 0
async for line in response.content:
line = line.decode('utf-8').strip()
if line.startswith('data: '):
try:
json_str = line[6:] # Remove 'data: ' prefix
chunk = json.loads(json_str)
if 'choices' in chunk and chunk['choices']:
delta = chunk['choices'][0].get('delta', {})
if 'content' in delta:
chunk = cls._filter_response(delta['content'])
if chunk:
yield chunk
idx += 1
except json.JSONDecodeError:
continue
if idx == 512:
yield FinishReason("length")
else:
# Non-streaming response
result = await response.json()
if "usage" in result:
yield Usage(**result["usage"])
if result["usage"]["completion_tokens"] == 512:
yield FinishReason("length")
if 'choices' in result and result['choices']:
message = result['choices'][0].get('message', {})
content = message.get('content', '')
filtered_response = cls._filter_response(content)
yield filtered_response
@classmethod
async def create_async_generator(
cls,
model: str,
messages: Messages,
prompt: str = None,
proxy: str = None,
max_tokens: int = 512,
temperature: float = 1,
top_p: float = 1,
stream: bool = True,
size: str = "1:1",
seed: int = None,
**kwargs
) -> AsyncResult:
model = cls.get_model(model)
if model in cls.image_models:
if prompt is None:
prompt = messages[-1]['content']
if seed is None:
seed = random.randint(0, 10000)
async for result in cls.generate_image(model, prompt, size, seed, proxy):
yield result
else:
async for result in cls.generate_text(model, messages, max_tokens, temperature, top_p, stream, proxy):
yield result