返回提交历史
Modified
g4f/Provider/Airforce.py
+332
-160
XFEstudio/gpt4free
refactor(g4f/Provider/Airforce.py): enhance Airforce provider functionality
6bf4c4bc
代码差异
1 个文件
+332
-160
@@ -1,76 +1,200 @@
1
1
from __future__ import annotations
2
3
from aiohttp import ClientSession, ClientResponseError
2
import random
4
3
import json
4
from aiohttp import ClientSession
5
5
from ..typing import AsyncResult, Messages
6
6
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
7
7
from ..image import ImageResponse
8
from .helper import format_prompt
9
from ..errors import ResponseStatusError
8
9
def split_long_message(message: str, max_length: int = 4000) -> list[str]:
10
return [message[i:i+max_length] for i in range(0, len(message), max_length)]
10
11
11
12
class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
13
label = "Airforce"
12
14
url = "https://api.airforce"
13
text_api_endpoint = "https://api.airforce/chat/completions"
14
15
image_api_endpoint = "https://api.airforce/imagine2"
16
text_api_endpoint = "https://api.airforce/chat/completions"
15
17
working = True
18
19
default_model = 'llama-3-70b-chat'
20
16
21
supports_gpt_35_turbo = True
17
22
supports_gpt_4 = True
18
23
supports_stream = True
19
24
supports_system_message = True
20
25
supports_message_history = True
21
default_model = 'llama-3-70b-chat'
26
22
27
text_models = [
23
# Open source models
24
'llama-2-13b-chat',
25
'llama-3-70b-chat',
26
'llama-3-70b-chat-turbo',
27
'llama-3-70b-chat-lite',
28
'llama-3-8b-chat',
29
'llama-3-8b-chat-turbo',
30
'llama-3-8b-chat-lite',
31
'llama-3.1-405b-turbo',
32
'llama-3.1-70b-turbo',
33
'llama-3.1-8b-turbo',
34
'LlamaGuard-2-8b',
35
'Llama-Guard-7b',
36
'Meta-Llama-Guard-3-8B',
37
'Mixtral-8x7B-Instruct-v0.1',
38
'Mixtral-8x22B-Instruct-v0.1',
39
'Mistral-7B-Instruct-v0.1',
40
'Mistral-7B-Instruct-v0.2',
41
'Mistral-7B-Instruct-v0.3',
42
'Qwen1.5-72B-Chat',
43
'Qwen1.5-110B-Chat',
44
'Qwen2-72B-Instruct',
45
'gemma-2b-it',
46
'gemma-2-9b-it',
47
'gemma-2-27b-it',
48
'dbrx-instruct',
49
'deepseek-llm-67b-chat',
50
'Nous-Hermes-2-Mixtral-8x7B-DPO',
51
'Nous-Hermes-2-Yi-34B',
52
'WizardLM-2-8x22B',
53
'SOLAR-10.7B-Instruct-v1.0',
54
'StripedHyena-Nous-7B',
55
'sparkdesk',
56
57
# Other models
58
'chatgpt-4o-latest',
59
'gpt-4',
60
'gpt-4-turbo',
61
'gpt-4o-mini-2024-07-18',
62
'gpt-4o-mini',
63
'gpt-4o',
64
'gpt-3.5-turbo',
65
'gpt-3.5-turbo-0125',
66
'gpt-3.5-turbo-1106',
67
'gpt-3.5-turbo-16k',
68
'gpt-3.5-turbo-0613',
69
'gpt-3.5-turbo-16k-0613',
70
'gemini-1.5-flash',
71
'gemini-1.5-pro',
28
# anthorpic
29
'claude-3-haiku-20240307',
30
'claude-3-sonnet-20240229',
31
'claude-3-5-sonnet-20240620',
32
'claude-3-opus-20240229',
33
34
# openai
35
'chatgpt-4o-latest',
36
'gpt-4',
37
#'gpt-4-0613',
38
'gpt-4-turbo',
39
'gpt-4o-mini-2024-07-18',
40
'gpt-4o-mini',
41
'gpt-3.5-turbo',
42
'gpt-3.5-turbo-0125',
43
'gpt-3.5-turbo-1106',
44
#'gpt-3.5-turbo-16k', # No response from the API.
45
#'gpt-3.5-turbo-0613', # No response from the API.
46
#'gpt-3.5-turbo-16k-0613', # No response from the API.
47
'gpt-4o',
48
#'o1-mini', # No response from the API.
49
50
# meta-llama
51
'llama-3-70b-chat',
52
'llama-3-70b-chat-turbo',
53
'llama-3-8b-chat',
54
'llama-3-8b-chat-turbo',
55
'llama-3-70b-chat-lite',
56
'llama-3-8b-chat-lite',
57
#'llama-2-70b-chat', # Failed to load response after multiple retries.
58
'llama-2-13b-chat',
59
#'llama-2-7b-chat', # Failed to load response after multiple retries.
60
'llama-3.1-405b-turbo',
61
'llama-3.1-70b-turbo',
62
'llama-3.1-8b-turbo',
63
'LlamaGuard-2-8b',
64
'Llama-Guard-7b',
65
'Llama-3.2-90B-Vision-Instruct-Turbo',
66
67
# codellama
68
#'CodeLlama-7b-Python-hf', # Failed to load response after multiple retries.
69
#'CodeLlama-7b-Python',
70
#'CodeLlama-13b-Python-hf', # Failed to load response after multiple retries.
71
#'CodeLlama-34b-Python-hf', # Failed to load response after multiple retries.
72
#'CodeLlama-70b-Python-hf', # Failed to load response after multiple retries.
73
74
# 01-ai
75
#'Yi-34B-Chat', # Failed to load response after multiple retries.
76
#'Yi-34B', # Failed to load response after multiple retries.
77
#'Yi-6B', # Failed to load response after multiple retries.
78
79
# mistral-ai
80
#'Mixtral-8x7B-v0.1',
81
#'Mixtral-8x22B', # Failed to load response after multiple retries.
82
'Mixtral-8x7B-Instruct-v0.1',
83
'Mixtral-8x22B-Instruct-v0.1',
84
'Mistral-7B-Instruct-v0.1',
85
'Mistral-7B-Instruct-v0.2',
86
'Mistral-7B-Instruct-v0.3',
87
88
# openchat
89
#'openchat-3.5', # Failed to load response after multiple retries.
90
91
# wizardlm
92
#'WizardLM-13B-V1.2', # Failed to load response after multiple retries.
93
#'WizardCoder-Python-34B-V1.0', # Failed to load response after multiple retries.
94
95
# qwen
96
#'Qwen1.5-0.5B-Chat', # Failed to load response after multiple retries.
97
#'Qwen1.5-1.8B-Chat', # Failed to load response after multiple retries.
98
#'Qwen1.5-4B-Chat', # Failed to load response after multiple retries.
99
'Qwen1.5-7B-Chat',
100
'Qwen1.5-14B-Chat',
101
'Qwen1.5-72B-Chat',
102
'Qwen1.5-110B-Chat',
103
'Qwen2-72B-Instruct',
104
105
# google
106
'gemma-2b-it',
107
#'gemma-7b-it', # Failed to load response after multiple retries.
108
#'gemma-2b', # Failed to load response after multiple retries.
109
#'gemma-7b', # Failed to load response after multiple retries.
110
'gemma-2-9b-it', # fix bug
111
'gemma-2-27b-it',
112
113
# gemini
114
'gemini-1.5-flash',
115
'gemini-1.5-pro',
116
117
# databricks
118
'dbrx-instruct',
119
120
# lmsys
121
#'vicuna-7b-v1.5', # Failed to load response after multiple retries.
122
#'vicuna-13b-v1.5', # Failed to load response after multiple retries.
123
124
# cognitivecomputations
125
#'dolphin-2.5-mixtral-8x7b', # Failed to load response after multiple retries.
126
127
# deepseek-ai
128
#'deepseek-coder-33b-instruct', # No response from the API.
129
#'deepseek-coder-67b-instruct', # Failed to load response after multiple retries.
130
'deepseek-llm-67b-chat',
131
132
# NousResearch
133
#'Nous-Capybara-7B-V1p9', # Failed to load response after multiple retries.
134
'Nous-Hermes-2-Mixtral-8x7B-DPO',
135
#'Nous-Hermes-2-Mixtral-8x7B-SFT', # Failed to load response after multiple retries.
136
#'Nous-Hermes-llama-2-7b', # Failed to load response after multiple retries.
137
#'Nous-Hermes-Llama2-13b', # Failed to load response after multiple retries.
138
'Nous-Hermes-2-Yi-34B',
139
140
# Open-Orca
141
#'Mistral-7B-OpenOrca', # Failed to load response after multiple retries.
142
143
# togethercomputer
144
#'alpaca-7b', # Failed to load response after multiple retries.
145
146
# teknium
147
#'OpenHermes-2-Mistral-7B', # Failed to load response after multiple retries.
148
#'OpenHermes-2.5-Mistral-7B', # Failed to load response after multiple retries.
149
150
# microsoft
151
'WizardLM-2-8x22B',
152
153
# Nexusflow
154
#'NexusRaven-V2-13B', # Failed to load response after multiple retries.
155
156
# Phind
157
#'Phind-CodeLlama-34B-v2', # Failed to load response after multiple retries.
158
159
# Snoflake
160
#'snowflake-arctic-instruct', # No response from the API.
161
162
# upstage
163
'SOLAR-10.7B-Instruct-v1.0',
164
165
# togethercomputer
166
#'StripedHyena-Hessian-7B', # Failed to load response after multiple retries.
167
#'StripedHyena-Nous-7B', # Failed to load response after multiple retries.
168
#'Llama-2-7B-32K-Instruct', # Failed to load response after multiple retries.
169
#'CodeLlama-13b-Instruct', # No response from the API.
170
#'evo-1-131k-base', # Failed to load response after multiple retries.
171
#'OLMo-7B-Instruct', # Failed to load response after multiple retries.
172
173
# garage-bAInd
174
#'Platypus2-70B-instruct', # Failed to load response after multiple retries.
175
176
# snorkelai
177
#'Snorkel-Mistral-PairRM-DPO', # Failed to load response after multiple retries.
178
179
# Undi95
180
#'ReMM-SLERP-L2-13B', # Failed to load response after multiple retries.
181
182
# Gryphe
183
'MythoMax-L2-13b',
184
185
# Autism
186
#'chronos-hermes-13b', # Failed to load response after multiple retries.
187
188
# Undi95
189
#'Toppy-M-7B', # Failed to load response after multiple retries.
190
191
# iFlytek
192
#'sparkdesk', # Failed to load response after multiple retries.
193
194
# pawan
195
'cosmosrp',
196
72
197
]
73
74
198
image_models = [
75
199
'flux',
76
200
'flux-realism',
@@ -85,158 +209,206 @@ class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
85
209
86
210
models = [
87
211
*text_models,
88
*image_models
212
*image_models,
89
213
]
90
214
model_aliases = {
91
# Open source models
92
"llama-2-13b": "llama-2-13b-chat",
215
# anthorpic
216
"claude-3-haiku": "claude-3-haiku-20240307",
217
"claude-3-sonnet": "claude-3-sonnet-20240229",
218
"claude-3-5-sonnet": "claude-3-5-sonnet-20240620",
219
"claude-3-opus": "claude-3-opus-20240229",
220
221
# openai
222
"gpt-4o": "chatgpt-4o-latest",
223
"gpt-4o-mini": "gpt-4o-mini-2024-07-18",
224
"gpt-3.5-turbo": "gpt-3.5-turbo-0125",
225
"gpt-3.5-turbo": "gpt-3.5-turbo-1106",
226
227
# meta-llama
93
228
"llama-3-70b": "llama-3-70b-chat",
94
229
"llama-3-70b": "llama-3-70b-chat-turbo",
95
"llama-3-70b": "llama-3-70b-chat-lite",
96
230
"llama-3-8b": "llama-3-8b-chat",
97
231
"llama-3-8b": "llama-3-8b-chat-turbo",
232
"llama-3-70b": "llama-3-70b-chat-lite",
98
233
"llama-3-8b": "llama-3-8b-chat-lite",
234
"llama-2-13b": "llama-2-13b-chat",
99
235
"llama-3.1-405b": "llama-3.1-405b-turbo",
100
236
"llama-3.1-70b": "llama-3.1-70b-turbo",
101
237
"llama-3.1-8b": "llama-3.1-8b-turbo",
238
"llamaguard-2-8b": "LlamaGuard-2-8b",
239
"llamaguard-7b": "Llama-Guard-7b",
240
"llama-3.2-90b": "Llama-3.2-90B-Vision-Instruct-Turbo",
241
242
# mistral-ai
102
243
"mixtral-8x7b": "Mixtral-8x7B-Instruct-v0.1",
103
244
"mixtral-8x22b": "Mixtral-8x22B-Instruct-v0.1",
104
245
"mistral-7b": "Mistral-7B-Instruct-v0.1",
105
246
"mistral-7b": "Mistral-7B-Instruct-v0.2",
106
247
"mistral-7b": "Mistral-7B-Instruct-v0.3",
107
"mixtral-8x7b-dpo": "Nous-Hermes-2-Mixtral-8x7B-DPO",
248
249
# qwen
250
"qwen-1.5-7b": "Qwen1.5-7B-Chat",
251
"qwen-1.5-14b": "Qwen1.5-14B-Chat",
108
252
"qwen-1.5-72b": "Qwen1.5-72B-Chat",
109
253
"qwen-1.5-110b": "Qwen1.5-110B-Chat",
110
254
"qwen-2-72b": "Qwen2-72B-Instruct",
255
256
# google
111
257
"gemma-2b": "gemma-2b-it",
112
"gemma-2b-9b": "gemma-2-9b-it",
113
"gemma-2b-27b": "gemma-2-27b-it",
258
"gemma-2-9b": "gemma-2-9b-it",
259
"gemma-2-27b": "gemma-2-27b-it",
260
261
# gemini
262
"gemini-flash": "gemini-1.5-flash",
263
"gemini-pro": "gemini-1.5-pro",
264
265
# deepseek-ai
114
266
"deepseek": "deepseek-llm-67b-chat",
267
268
# NousResearch
269
"mixtral-8x7b-dpo": "Nous-Hermes-2-Mixtral-8x7B-DPO",
115
270
"yi-34b": "Nous-Hermes-2-Yi-34B",
271
272
# microsoft
116
273
"wizardlm-2-8x22b": "WizardLM-2-8x22B",
117
"solar-10-7b": "SOLAR-10.7B-Instruct-v1.0",
118
"sh-n-7b": "StripedHyena-Nous-7B",
119
"sparkdesk-v1.1": "sparkdesk",
120
274
121
# Other models
122
"gpt-4o": "chatgpt-4o-latest",
123
"gpt-4o-mini": "gpt-4o-mini-2024-07-18",
124
"gpt-3.5-turbo": "gpt-3.5-turbo-0125",
125
"gpt-3.5-turbo": "gpt-3.5-turbo-1106",
126
"gpt-3.5-turbo": "gpt-3.5-turbo-16k",
127
"gpt-3.5-turbo": "gpt-3.5-turbo-0613",
128
"gpt-3.5-turbo": "gpt-3.5-turbo-16k-0613",
129
"gemini-flash": "gemini-1.5-flash",
130
"gemini-pro": "gemini-1.5-pro",
275
# upstage
276
"solar-10.7b": "SOLAR-10.7B-Instruct-v1.0",
131
277
132
# Image models
133
"dalle-3": "dall-e-3",
278
# Gryphe
279
"mythomax-l2-13b": "MythoMax-L2-13b",
134
280
}
135
281
282
@classmethod
283
def get_model(cls, model: str) -> str:
284
if model in cls.models:
285
return model
286
elif model in cls.model_aliases:
287
return cls.model_aliases.get(model, cls.default_model)
288
else:
289
return cls.default_model
290
136
291
@classmethod
137
292
async def create_async_generator(
138
293
cls,
139
294
model: str,
140
295
messages: Messages,
141
296
proxy: str = None,
297
seed: int = None,
298
size: str = "1:1",
299
stream: bool = False,
142
300
**kwargs
143
301
) -> AsyncResult:
144
302
model = cls.get_model(model)
145
303
304
# If the model is an image model, use the image API
305
if model in cls.image_models:
306
async for result in cls._generate_image(model, messages, proxy, seed, size):
307
yield result
308
# If the model is a text model, use the text API
309
elif model in cls.text_models:
310
async for result in cls._generate_text(model, messages, proxy, stream):
311
yield result
312
313
@classmethod
314
async def _generate_image(
315
cls,
316
model: str,
317
messages: Messages,
318
proxy: str = None,
319
seed: int = None,
320
size: str = "1:1",
321
**kwargs
322
) -> AsyncResult:
146
323
headers = {
147
324
"accept": "*/*",
148
325
"accept-language": "en-US,en;q=0.9",
149
"content-type": "application/json",
150
"origin": "https://api.airforce",
151
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
152
"authorization": "Bearer null",
153
326
"cache-control": "no-cache",
154
"pragma": "no-cache",
155
"priority": "u=1, i",
156
"referer": "https://llmplayground.net/",
157
"sec-ch-ua": '"Not;A=Brand";v="24", "Chromium";v="128"',
158
"sec-ch-ua-mobile": "?0",
159
"sec-ch-ua-platform": '"Linux"',
160
"sec-fetch-dest": "empty",
161
"sec-fetch-mode": "cors",
162
"sec-fetch-site": "cross-site",
327
"origin": "https://llmplayground.net",
328
"user-agent": "Mozilla/5.0"
163
329
}
164
330
165
if model in cls.image_models:
166
async for item in cls.generate_image(model, messages, headers, proxy, **kwargs):
167
yield item
168
else:
169
async for item in cls.generate_text(model, messages, headers, proxy, **kwargs):
170
yield item
331
if seed is None:
332
seed = random.randint(0, 100000)
171
333
172
@classmethod
173
async def generate_text(cls, model: str, messages: Messages, headers: dict, proxy: str, **kwargs) -> AsyncResult:
174
async with ClientSession() as session:
175
data = {
176
"messages": [{"role": "user", "content": message['content']} for message in messages],
334
# Assume the first message is the prompt for the image
335
prompt = messages[0]['content']
336
337
async with ClientSession(headers=headers) as session:
338
params = {
177
339
"model": model,
178
"max_tokens": kwargs.get('max_tokens', 4096),
179
"temperature": kwargs.get('temperature', 1),
180
"top_p": kwargs.get('top_p', 1),
181
"stream": True
340
"prompt": prompt,
341
"size": size,
342
"seed": seed
182
343
}
344
async with session.get(f"{cls.image_api_endpoint}", params=params, proxy=proxy) as response:
345
response.raise_for_status()
346
content_type = response.headers.get('Content-Type', '').lower()
183
347
184
try:
185
async with session.post(cls.text_api_endpoint, json=data, headers=headers, proxy=proxy) as response:
186
response.raise_for_status()
187
async for line in response.content:
188
if line:
189
line = line.decode('utf-8').strip()
190
if line.startswith("data: "):
191
if line == "data: [DONE]":
192
break
193
try:
194
data = json.loads(line[6:])
195
if 'choices' in data and len(data['choices']) > 0:
196
delta = data['choices'][0].get('delta', {})
197
if 'content' in delta:
198
content = delta['content']
199
if "One message exceeds the 1000chars per message limit" in content:
200
raise ResponseStatusError(
201
"Message too long",
202
400,
203
"Please try a shorter message."
204
)
205
yield content
206
except json.JSONDecodeError:
207
continue
208
except ResponseStatusError as e:
209
raise e
210
except Exception as e:
211
raise ResponseStatusError(str(e), 500, "An unexpected error occurred")
348
if 'application/json' in content_type:
349
async for chunk in response.content.iter_chunked(1024):
350
if chunk:
351
yield chunk.decode('utf-8')
352
elif 'image' in content_type:
353
image_data = b""
354
async for chunk in response.content.iter_chunked(1024):
355
if chunk:
356
image_data += chunk
357
image_url = f"{cls.image_api_endpoint}?model={model}&prompt={prompt}&size={size}&seed={seed}"
358
alt_text = f"Generated image for prompt: {prompt}"
359
yield ImageResponse(images=image_url, alt=alt_text)
212
360
213
361
@classmethod
214
async def generate_image(cls, model: str, messages: Messages, headers: dict, proxy: str, **kwargs) -> AsyncResult:
215
prompt = messages[-1]['content'] if messages else ""
216
params = {
217
"prompt": prompt,
218
"size": kwargs.get("size", "1:1"),
219
"seed": kwargs.get("seed"),
220
"model": model
362
async def _generate_text(
363
cls,
364
model: str,
365
messages: Messages,
366
proxy: str = None,
367
stream: bool = False,
368
**kwargs
369
) -> AsyncResult:
370
headers = {
371
"accept": "*/*",
372
"accept-language": "en-US,en;q=0.9",
373
"authorization": "Bearer missing api key",
374
"content-type": "application/json",
375
"user-agent": "Mozilla/5.0"
221
376
}
222
params = {k: v for k, v in params.items() if v is not None}
223
377
224
try:
225
async with ClientSession(headers=headers) as session:
226
async with session.get(cls.image_api_endpoint, params=params, proxy=proxy) as response:
378
async with ClientSession(headers=headers) as session:
379
formatted_prompt = cls._format_messages(messages)
380
prompt_parts = split_long_message(formatted_prompt)
381
full_response = ""
382
383
for part in prompt_parts:
384
data = {
385
"messages": [{"role": "user", "content": part}],
386
"model": model,
387
"max_tokens": 4096,
388
"temperature": 1,
389
"top_p": 1,
390
"stream": stream
391
}
392
async with session.post(cls.text_api_endpoint, json=data, proxy=proxy) as response:
227
393
response.raise_for_status()
228
content = await response.read()
229
230
if response.content_type.startswith('image/'):
231
image_url = str(response.url)
232
yield ImageResponse(image_url, prompt)
394
part_response = ""
395
if stream:
396
async for line in response.content:
397
if line:
398
line = line.decode('utf-8').strip()
399
if line.startswith("data: ") and line != "data: [DONE]":
400
json_data = json.loads(line[6:])
401
content = json_data['choices'][0]['delta'].get('content', '')
402
part_response += content
233
403
else:
234
try:
235
text = content.decode('utf-8', errors='ignore')
236
raise ResponseStatusError("Image generation failed", response.status, text)
237
except Exception as decode_error:
238
raise ResponseStatusError("Decoding error", 500, str(decode_error))
239
except ClientResponseError as e:
240
raise ResponseStatusError(f"HTTP {e.status}", e.status, e.message)
241
except Exception as e:
242
raise ResponseStatusError("Unexpected error", 500, str(e))
404
json_data = await response.json()
405
content = json_data['choices'][0]['message']['content']
406
part_response = content
407
408
full_response += part_response
409
yield full_response
410
411
@classmethod
412
def _format_messages(cls, messages: Messages) -> str:
413
"""Formats messages for text generation."""
414
return " ".join([msg['content'] for msg in messages])