XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 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
Heiner Lohaus <hlohaus@users.noreply.github.com>
提交于

代码差异

11 个文件 +157 -55
Modified README.md +1 -1
@@ -21,7 +21,7 @@
21 21 > <sup><strong>Stats:</strong></sup> [![Downloads](https://static.pepy.tech/badge/g4f)](https://pepy.tech/project/g4f) [![Downloads](https://static.pepy.tech/badge/g4f/month)](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
Modified g4f/Provider/Blackbox.py +30 -35
@@ -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()
Added g4f/Provider/Copilot.py +87 -0
@@ -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
Modified g4f/Provider/DeepInfraChat.py +0 -2
@@ -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"
Modified g4f/Provider/__init__.py +1 -0
@@ -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
Modified g4f/Provider/airforce/AirforceChat.py +6 -4
@@ -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
Modified g4f/Provider/needs_auth/OpenaiChat.py +15 -1
@@ -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,
Modified g4f/gui/client/index.html +1 -0
@@ -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>
Modified g4f/gui/client/static/js/chat.v1.js +3 -2
@@ -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:")) {
Modified g4f/gui/server/api.py +12 -9
@@ -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 }
Modified g4f/requests/__init__.py +1 -1
@@ -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,