返回提交历史
Modified
README.md
+1
-1
Modified
g4f/Provider/Blackbox.py
+30
-35
Added
g4f/Provider/Copilot.py
+87
-0
Modified
g4f/Provider/DeepInfraChat.py
+0
-2
Modified
g4f/Provider/__init__.py
+1
-0
Modified
g4f/Provider/airforce/AirforceChat.py
+6
-4
Modified
g4f/Provider/needs_auth/OpenaiChat.py
+15
-1
Modified
g4f/gui/client/index.html
+1
-0
Modified
g4f/gui/client/static/js/chat.v1.js
+3
-2
Modified
g4f/gui/server/api.py
+12
-9
Modified
g4f/requests/__init__.py
+1
-1
XFEstudio/gpt4free
Fix load model list i AirforceChat provider Add Microsoft Copilot provider Show image support in the model list of the gui
f1ef2328
代码差异
11 个文件
+157
-55
@@ -21,7 +21,7 @@
21
21
> <sup><strong>Stats:</strong></sup> [](https://pepy.tech/project/g4f) [](https://pepy.tech/project/g4f)
22
22
23
23
```sh
24
pip install -U g4f
24
pip install -U g4f[all]
25
25
```
26
26
27
27
```sh
@@ -10,6 +10,7 @@ import aiohttp
10
10
from ..typing import AsyncResult, Messages, ImageType
11
11
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
12
12
from ..image import ImageResponse, to_data_uri
13
from .helper import get_random_string
13
14
14
15
class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
15
16
label = "Blackbox AI"
@@ -22,11 +23,13 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
22
23
_last_validated_value = None
23
24
24
25
default_model = 'blackboxai'
26
default_vision_model = default_model
25
27
default_image_model = 'generate_image'
26
28
image_models = [default_image_model, 'repomap']
27
29
text_models = [default_model, 'gpt-4o', 'gemini-pro', 'claude-sonnet-3.5', 'blackboxai-pro']
30
vision_models = [default_model, 'gpt-4o', 'gemini-pro', 'blackboxai-pro']
28
31
agentMode = {
29
'Image Generation': {'mode': True, 'id': "ImageGenerationLV45LJp", 'name': "Image Generation"},
32
default_image_model: {'mode': True, 'id': "ImageGenerationLV45LJp", 'name': "Image Generation"},
30
33
}
31
34
trendingAgentMode = {
32
35
"gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
@@ -111,11 +114,6 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
111
114
112
115
return cls._last_validated_value
113
116
114
@staticmethod
115
def generate_id(length=7):
116
characters = string.ascii_letters + string.digits
117
return ''.join(random.choice(characters) for _ in range(length))
118
119
117
@classmethod
120
118
def add_prefix_to_messages(cls, messages: Messages, model: str) -> Messages:
121
119
prefix = cls.model_prefixes.get(model, "")
@@ -143,12 +141,12 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
143
141
**kwargs
144
142
) -> AsyncResult:
145
143
model = cls.get_model(model)
146
message_id = cls.generate_id()
147
messages_with_prefix = cls.add_prefix_to_messages(messages, model)
144
message_id = get_random_string(7)
145
messages = cls.add_prefix_to_messages(messages, model)
148
146
validated_value = await cls.fetch_validated()
149
147
150
148
if image is not None:
151
messages_with_prefix[-1]['data'] = {
149
messages[-1]['data'] = {
152
150
'fileText': '',
153
151
'imageBase64': to_data_uri(image),
154
152
'title': image_name
@@ -171,9 +169,9 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
171
169
'sec-fetch-site': 'same-origin',
172
170
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36'
173
171
}
174
172
175
173
data = {
176
"messages": messages_with_prefix,
174
"messages": messages,
177
175
"id": message_id,
178
176
"previewToken": None,
179
177
"userId": None,
@@ -200,27 +198,24 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
200
198
async with ClientSession(headers=headers) as session:
201
199
async with session.post(cls.api_endpoint, json=data, proxy=proxy) as response:
202
200
response.raise_for_status()
203
response_text = await response.text()
204
205
if model in cls.image_models:
206
image_matches = re.findall(r'!\[.*?\]\((https?://[^\)]+)\)', response_text)
207
if image_matches:
208
image_url = image_matches[0]
209
image_response = ImageResponse(images=[image_url], alt="Generated Image")
210
yield image_response
211
return
212
213
response_text = re.sub(r'Generated by BLACKBOX.AI, try unlimited chat https://www.blackbox.ai', '', response_text, flags=re.DOTALL)
214
215
json_match = re.search(r'\$~~~\$(.*?)\$~~~\$', response_text, re.DOTALL)
216
if json_match:
217
search_results = json.loads(json_match.group(1))
218
answer = response_text.split('$~~~$')[-1].strip()
219
220
formatted_response = f"{answer}\n\n**Source:**"
221
for i, result in enumerate(search_results, 1):
222
formatted_response += f"\n{i}. {result['title']}: {result['link']}"
223
224
yield formatted_response
225
else:
226
yield response_text.strip()
201
async for chunk in response.content.iter_any():
202
text_chunk = chunk.decode(errors="ignore")
203
if model in cls.image_models:
204
image_matches = re.findall(r'!\[.*?\]\((https?://[^\)]+)\)', text_chunk)
205
if image_matches:
206
image_url = image_matches[0]
207
image_response = ImageResponse(images=[image_url])
208
yield image_response
209
continue
210
211
text_chunk = re.sub(r'Generated by BLACKBOX.AI, try unlimited chat https://www.blackbox.ai', '', text_chunk, flags=re.DOTALL)
212
json_match = re.search(r'\$~~~\$(.*?)\$~~~\$', text_chunk, re.DOTALL)
213
if json_match:
214
search_results = json.loads(json_match.group(1))
215
answer = text_chunk.split('$~~~$')[-1].strip()
216
formatted_response = f"{answer}\n\n**Source:**"
217
for i, result in enumerate(search_results, 1):
218
formatted_response += f"\n{i}. {result['title']}: {result['link']}"
219
yield formatted_response
220
else:
221
yield text_chunk.strip()
@@ -0,0 +1,87 @@
1
from __future__ import annotations
2
3
import json
4
from http.cookiejar import CookieJar
5
try:
6
from curl_cffi.requests import Session, CurlWsFlag
7
has_curl_cffi = True
8
except ImportError:
9
has_curl_cffi = False
10
11
from .base_provider import AbstractProvider, BaseConversation
12
from .helper import format_prompt
13
from ..typing import CreateResult, Messages
14
from ..errors import MissingRequirementsError
15
from ..requests.raise_for_status import raise_for_status
16
from .. import debug
17
18
class Conversation(BaseConversation):
19
conversation_id: str
20
cookie_jar: CookieJar
21
22
def __init__(self, conversation_id: str, cookie_jar: CookieJar):
23
self.conversation_id = conversation_id
24
self.cookie_jar = cookie_jar
25
26
class Copilot(AbstractProvider):
27
label = "Microsoft Copilot"
28
url = "https://copilot.microsoft.com"
29
working = True
30
supports_stream = True
31
32
websocket_url = "wss://copilot.microsoft.com/c/api/chat?api-version=2"
33
conversation_url = f"{url}/c/api/conversations"
34
35
@classmethod
36
def create_completion(
37
cls,
38
model: str,
39
messages: Messages,
40
stream: bool = False,
41
proxy: str = None,
42
timeout: int = 900,
43
conversation: Conversation = None,
44
return_conversation: bool = False,
45
**kwargs
46
) -> CreateResult:
47
if not has_curl_cffi:
48
raise MissingRequirementsError('Install or update "curl_cffi" package | pip install -U nodriver')
49
50
cookies = conversation.cookie_jar if conversation is not None else None
51
with Session(timeout=timeout, proxy=proxy, impersonate="chrome", cookies=cookies) as session:
52
response = session.get(f"{cls.url}/")
53
raise_for_status(response)
54
if conversation is None:
55
response = session.post(cls.conversation_url)
56
raise_for_status(response)
57
conversation_id = response.json().get("id")
58
if return_conversation:
59
yield Conversation(conversation_id, session.cookies.jar)
60
prompt = format_prompt(messages)
61
if debug.logging:
62
print(f"Copilot: Created conversation: {conversation_id}")
63
else:
64
conversation_id = conversation.conversation_id
65
prompt = messages[-1]["content"]
66
if debug.logging:
67
print(f"Copilot: Use conversation: {conversation_id}")
68
69
wss = session.ws_connect(cls.websocket_url)
70
wss.send(json.dumps({
71
"event": "send",
72
"conversationId": conversation_id,
73
"content": [{
74
"type": "text",
75
"text": prompt,
76
}],
77
"mode": "chat"
78
}).encode(), CurlWsFlag.TEXT)
79
while True:
80
try:
81
msg = json.loads(wss.recv()[0])
82
except:
83
break
84
if msg.get("event") == "appendText":
85
yield msg.get("text")
86
elif msg.get("event") in ["done", "partCompleted"]:
87
break
@@ -4,10 +4,8 @@ from aiohttp import ClientSession
4
4
import json
5
5
6
6
from ..typing import AsyncResult, Messages, ImageType
7
from ..image import to_data_uri
8
7
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
9
8
10
11
9
class DeepInfraChat(AsyncGeneratorProvider, ProviderModelMixin):
12
10
url = "https://deepinfra.com/chat"
13
11
api_endpoint = "https://api.deepinfra.com/v1/openai/chat/completions"
@@ -19,6 +19,7 @@ from .Blackbox import Blackbox
19
19
from .ChatGpt import ChatGpt
20
20
from .ChatGptEs import ChatGptEs
21
21
from .Cloudflare import Cloudflare
22
from .Copilot import Copilot
22
23
from .DarkAI import DarkAI
23
24
from .DDG import DDG
24
25
from .DeepInfraChat import DeepInfraChat
@@ -50,11 +50,13 @@ class AirforceChat(AsyncGeneratorProvider, ProviderModelMixin):
50
50
supports_message_history = True
51
51
52
52
default_model = 'llama-3.1-70b-chat'
53
response = requests.get('https://api.airforce/models')
54
data = response.json()
55
53
56
text_models = [model['id'] for model in data['data']]
57
models = [*text_models]
54
@classmethod
55
def get_models(cls) -> list:
56
if not cls.models:
57
response = requests.get('https://api.airforce/models')
58
data = response.json()
59
cls.models = [model['id'] for model in data['data']]
58
60
59
61
model_aliases = {
60
62
# openchat
@@ -6,6 +6,7 @@ import uuid
6
6
import json
7
7
import base64
8
8
import time
9
import requests
9
10
from aiohttp import ClientWebSocketResponse
10
11
from copy import copy
11
12
@@ -62,13 +63,26 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
62
63
supports_system_message = True
63
64
default_model = "auto"
64
65
default_vision_model = "gpt-4o"
65
models = ["auto", "gpt-4o-mini", "gpt-4o", "gpt-4", "gpt-4-gizmo"]
66
fallback_models = ["auto", "gpt-4", "gpt-4o", "gpt-4o-mini", "gpt-4o-canmore", "o1-preview", "o1-mini"]
67
vision_models = fallback_models
66
68
67
69
_api_key: str = None
68
70
_headers: dict = None
69
71
_cookies: Cookies = None
70
72
_expires: int = None
71
73
74
@classmethod
75
def get_models(cls):
76
if not cls.models:
77
try:
78
response = requests.get(f"{cls.url}/backend-anon/models")
79
response.raise_for_status()
80
data = response.json()
81
cls.models = [model.get("slug") for model in data.get("models")]
82
except Exception:
83
cls.models = cls.fallback_models
84
return cls.models
85
72
86
@classmethod
73
87
async def create(
74
88
cls,
@@ -245,6 +245,7 @@
245
245
<select name="provider" id="provider">
246
246
<option value="">Provider: Auto</option>
247
247
<option value="OpenaiChat">OpenAI ChatGPT</option>
248
<option value="Copilot">Microsoft Copilot</option>
248
249
<option value="ChatGpt">ChatGpt</option>
249
250
<option value="Gemini">Gemini</option>
250
251
<option value="MetaAI">Meta AI</option>
@@ -1367,7 +1367,8 @@ async function load_provider_models(providerIndex=null) {
1367
1367
modelProvider.classList.remove("hidden");
1368
1368
models.forEach((model) => {
1369
1369
let option = document.createElement('option');
1370
option.value = option.text = model.model;
1370
option.value = model.model;
1371
option.text = `${model.model}${model.image ? " (Image Generation)" : ""}${model.vision ? " (Image Upload)" : ""}`;
1371
1372
option.selected = model.default;
1372
1373
modelProvider.appendChild(option);
1373
1374
});
@@ -1381,7 +1382,7 @@ providerSelect.addEventListener("change", () => load_provider_models());
1381
1382
function save_storage() {
1382
1383
let filename = `chat ${new Date().toLocaleString()}.json`.replaceAll(":", "-");
1383
1384
let data = {"options": {"g4f": ""}};
1384
for (let i = 0; i < appStorage.length; i++){
1385
for (let i = 0; i < appStorage.length; i++){label
1385
1386
let key = appStorage.key(i);
1386
1387
let item = appStorage.getItem(key);
1387
1388
if (key.startsWith("conversation:")) {
@@ -42,7 +42,12 @@ class Api:
42
42
provider: ProviderType = __map__[provider]
43
43
if issubclass(provider, ProviderModelMixin):
44
44
return [
45
{"model": model, "default": model == provider.default_model}
45
{
46
"model": model,
47
"default": model == provider.default_model,
48
"vision": getattr(provider, "default_vision_model", None) == model or model in getattr(provider, "vision_models", []),
49
"image": model in getattr(provider, "image_models", []),
50
}
46
51
for model in provider.get_models()
47
52
]
48
53
return []
@@ -65,7 +70,7 @@ class Api:
65
70
"url": parent.url,
66
71
"label": parent.label if hasattr(parent, "label") else None,
67
72
"image_model": model,
68
"vision_model": parent.default_vision_model if hasattr(parent, "default_vision_model") else None
73
"vision_model": getattr(parent, "default_vision_model", None)
69
74
})
70
75
index.append(parent.__name__)
71
76
elif hasattr(provider, "default_vision_model") and provider.__name__ not in index:
@@ -82,13 +87,11 @@ class Api:
82
87
@staticmethod
83
88
def get_providers() -> list[str]:
84
89
return {
85
provider.__name__: (
86
provider.label if hasattr(provider, "label") else provider.__name__
87
) + (
88
" (WebDriver)" if "webdriver" in provider.get_parameters() else ""
89
) + (
90
" (Auth)" if provider.needs_auth else ""
91
)
90
provider.__name__: (provider.label if hasattr(provider, "label") else provider.__name__)
91
+ (" (Image Generation)" if hasattr(provider, "image_models") else "")
92
+ (" (Image Upload)" if getattr(provider, "default_vision_model", None) else "")
93
+ (" (WebDriver)" if "webdriver" in provider.get_parameters() else "")
94
+ (" (Auth)" if provider.needs_auth else "")
92
95
for provider in __providers__
93
96
if provider.working
94
97
}
@@ -109,7 +109,7 @@ def get_args_from_browser(
109
109
110
110
def get_session_from_browser(url: str, webdriver: WebDriver = None, proxy: str = None, timeout: int = 120) -> Session:
111
111
if not has_curl_cffi:
112
raise MissingRequirementsError('Install "curl_cffi" package')
112
raise MissingRequirementsError('Install "curl_cffi" package | pip install -U curl_cffi')
113
113
args = get_args_from_browser(url, webdriver, proxy, timeout)
114
114
return Session(
115
115
**args,