XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/gpt4free

Remove webview js api, Add unittest for provider has model, Use cooki… (#2470)

* Remove webview js api, Add unittest for provider has model, Use cookies dir for cache

76c36834
H Lohaus <hlohaus@users.noreply.github.com>
提交于

代码差异

18 个文件 +63 -293
Modified etc/tool/create_provider.py +1 -1
@@ -113,7 +113,7 @@ And replace "gpt-3.5-turbo" with `model`.
113 113 print("Create code...")
114 114 response = []
115 115 for chunk in g4f.ChatCompletion.create(
116 model=g4f.models.default,
116 model=g4f.models.gpt_4o,
117 117 messages=[{"role": "user", "content": prompt}],
118 118 timeout=300,
119 119 stream=True,
Modified etc/unittest/__main__.py +1 -0
@@ -8,5 +8,6 @@ from .client import *
8 8 from .image_client import *
9 9 from .include import *
10 10 from .retry_provider import *
11 from .models import *
11 12
12 13 unittest.main()
Modified etc/unittest/model.py +4 -4
@@ -4,24 +4,24 @@ from g4f import ChatCompletion
4 4 from .mocks import ModelProviderMock
5 5
6 6 DEFAULT_MESSAGES = [{'role': 'user', 'content': 'Hello'}]
7
7
8 8 test_model = g4f.models.Model(
9 9 name = "test/test_model",
10 10 base_provider = "",
11 11 best_provider = ModelProviderMock
12 12 )
13 13 g4f.models.ModelUtils.convert["test_model"] = test_model
14
14
15 15 class TestPassModel(unittest.TestCase):
16 16
17 17 def test_model_instance(self):
18 18 response = ChatCompletion.create(test_model, DEFAULT_MESSAGES)
19 19 self.assertEqual(test_model.name, response)
20
20
21 21 def test_model_name(self):
22 22 response = ChatCompletion.create("test_model", DEFAULT_MESSAGES)
23 23 self.assertEqual(test_model.name, response)
24
24
25 25 def test_model_pass(self):
26 26 response = ChatCompletion.create("test/test_model", DEFAULT_MESSAGES, ModelProviderMock)
27 27 self.assertEqual(test_model.name, response)
Added etc/unittest/models.py +23 -0
@@ -0,0 +1,23 @@
1 import unittest
2 from typing import Type
3 import asyncio
4
5 from g4f.models import __models__
6 from g4f.providers.base_provider import BaseProvider, ProviderModelMixin
7 from g4f.models import Model
8
9 class TestProviderHasModel(unittest.IsolatedAsyncioTestCase):
10 cache: dict = {}
11
12 async def test_provider_has_model(self):
13 for model, providers in __models__.values():
14 for provider in providers:
15 if issubclass(provider, ProviderModelMixin):
16 if model.name not in provider.model_aliases:
17 await asyncio.wait_for(self.provider_has_model(provider, model), 10)
18
19 async def provider_has_model(self, provider: Type[BaseProvider], model: Model):
20 if provider.__name__ not in self.cache:
21 self.cache[provider.__name__] = provider.get_models()
22 if self.cache[provider.__name__]:
23 self.assertIn(model.name, self.cache[provider.__name__], provider.__name__)
Modified g4f/Provider/Airforce.py +1 -1
@@ -60,6 +60,7 @@ class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
60 60 "evil": "any-uncensored",
61 61 "sdxl": "stable-diffusion-xl-base",
62 62 "flux-pro": "flux-1.1-pro",
63 "llama-3.1-8b": "llama-3.1-8b-chat"
63 64 }
64 65
65 66 @classmethod
@@ -85,7 +86,6 @@ class Airforce(AsyncGeneratorProvider, ProviderModelMixin):
85 86 cls.models = [model for model in cls.models if model not in cls.hidden_models]
86 87 except Exception as e:
87 88 debug.log(f"Error fetching text models: {e}")
88 cls.models = [cls.default_model]
89 89
90 90 return cls.models
91 91
Modified g4f/Provider/Blackbox.py +6 -15
@@ -7,21 +7,20 @@ import json
7 7 import re
8 8 import aiohttp
9 9
10 import os
11 10 import json
12 11 from pathlib import Path
13 12
14 13 from ..typing import AsyncResult, Messages, ImageType
15 14 from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
16 15 from ..image import ImageResponse, to_data_uri
17
16 from ..cookies import get_cookies_dir
18 17 from .helper import format_prompt
19 18
20 19 class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
21 20 label = "Blackbox AI"
22 21 url = "https://www.blackbox.ai"
23 22 api_endpoint = "https://www.blackbox.ai/api/chat"
24
23
25 24 working = True
26 25 supports_stream = True
27 26 supports_system_message = True
@@ -38,7 +37,7 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
38 37 agentMode = {
39 38 'ImageGeneration': {'mode': True, 'id': "ImageGenerationLV45LJp", 'name': "Image Generation"}
40 39 }
41
40
42 41 trendingAgentMode = {
43 42 "gemini-1.5-flash": {'mode': True, 'id': 'Gemini'},
44 43 "llama-3.1-8b": {'mode': True, 'id': "llama-3.1-8b"},
@@ -108,19 +107,11 @@ class Blackbox(AsyncGeneratorProvider, ProviderModelMixin):
108 107 "flux": "ImageGeneration",
109 108 }
110 109
111 @classmethod
112 def _get_cache_dir(cls) -> Path:
113 # Get the path to the current file
114 current_file = Path(__file__)
115 # Create the path to the .cache directory
116 cache_dir = current_file.parent / '.cache'
117 # Create a directory if it does not exist
118 cache_dir.mkdir(exist_ok=True)
119 return cache_dir
120
121 110 @classmethod
122 111 def _get_cache_file(cls) -> Path:
123 return cls._get_cache_dir() / 'blackbox.json'
112 dir = Path(get_cookies_dir())
113 dir.mkdir(exist_ok=True)
114 return dir / 'blackbox.json'
124 115
125 116 @classmethod
126 117 def _load_cached_value(cls) -> str | None:
Modified g4f/Provider/Flux.py +1 -1
@@ -12,7 +12,7 @@ class Flux(AsyncGeneratorProvider, ProviderModelMixin):
12 12 url = "https://black-forest-labs-flux-1-dev.hf.space"
13 13 api_endpoint = "/gradio_api/call/infer"
14 14 working = True
15 default_model = 'flux-1-dev'
15 default_model = 'flux-dev'
16 16 models = [default_model]
17 17 image_models = [default_model]
18 18
Modified g4f/Provider/RobocodersAPI.py +2 -1
@@ -14,6 +14,7 @@ except ImportError:
14 14 from aiohttp import ClientTimeout
15 15 from ..errors import MissingRequirementsError
16 16 from ..typing import AsyncResult, Messages
17 from ..cookies import get_cookies_dir
17 18 from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
18 19 from .helper import format_prompt
19 20
@@ -30,7 +31,7 @@ class RobocodersAPI(AsyncGeneratorProvider, ProviderModelMixin):
30 31 agent = [default_model, "RepoAgent", "FrontEndAgent"]
31 32 models = [*agent]
32 33
33 CACHE_DIR = Path(__file__).parent / ".cache"
34 CACHE_DIR = Path(get_cookies_dir())
34 35 CACHE_FILE = CACHE_DIR / "robocoders.json"
35 36
36 37 @classmethod
Modified g4f/Provider/needs_auth/CopilotAccount.py +4 -1
@@ -9,4 +9,7 @@ class CopilotAccount(Copilot, ProviderModelMixin):
9 9 default_model = "Copilot"
10 10 default_vision_model = default_model
11 11 models = [default_model]
12 image_models = models
12 image_models = models
13 model_aliases = {
14 "dall-e-3": default_model
15 }
Modified g4f/Provider/needs_auth/MetaAI.py +1 -1
@@ -29,7 +29,7 @@ class MetaAI(AsyncGeneratorProvider, ProviderModelMixin):
29 29 label = "Meta AI"
30 30 url = "https://www.meta.ai"
31 31 working = True
32 default_model = ''
32 default_model = 'meta-ai'
33 33
34 34 def __init__(self, proxy: str = None, connector: BaseConnector = None):
35 35 self.session = ClientSession(connector=get_connector(connector, proxy), headers=DEFAULT_HEADERS)
Modified g4f/gui/client/index.html +8 -18
@@ -1,6 +1,5 @@
1 1 <!DOCTYPE html>
2 2 <html lang="en" data-framework="javascript">
3
4 3 <head>
5 4 <meta charset="UTF-8">
6 5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
@@ -62,9 +61,8 @@
62 61 onInit: (el, pswp) => {
63 62 lightbox.pswp.on('change', () => {
64 63 const currSlideElement = lightbox.pswp.currSlide.data.element;
65 let captionHTML = '';
66 64 if (currSlideElement) {
67 el.innerHTML = currSlideElement.querySelector('img').getAttribute('alt');
65 el.innerText = currSlideElement.querySelector('img').getAttribute('alt');
68 66 }
69 67 });
70 68 }
@@ -80,7 +78,6 @@
80 78 <script>window.conversation_id = "{{chat_id}}"</script>
81 79 <title>g4f - gui</title>
82 80 </head>
83
84 81 <body>
85 82 <div class="gradient"></div>
86 83 <div class="row">
@@ -92,12 +89,6 @@
92 89 </button>
93 90 </div>
94 91 <div class="bottom_buttons">
95 <!--
96 <button onclick="open_album();">
97 <i class="fa-solid fa-toolbox"></i>
98 <span>Images Album</span>
99 </button>
100 -->
101 92 <button onclick="open_settings();">
102 93 <i class="fa-solid fa-toolbox"></i>
103 94 <span>Open Settings</span>
@@ -118,8 +109,6 @@
118 109 </div>
119 110 </div>
120 111 </div>
121 <div class="images hidden">
122 </div>
123 112 <div class="settings hidden">
124 113 <div class="paper">
125 114 <h3>Settings</h3>
@@ -151,14 +140,14 @@
151 140 <div class="field">
152 141 <span class="label">Auto continue in ChatGPT</span>
153 142 <input id="auto_continue" type="checkbox" name="auto_continue" checked/>
154 <label for="auto_continue" class="toogle" title="Continue large responses in OpenaiChat"></label>
143 <label for="auto_continue" class="toogle" title="Continue large responses in OpenAI ChatGPT"></label>
155 144 </div>
156 145 <div class="field box">
157 146 <label for="message-input-height" class="label" title="">Input max. height</label>
158 147 <input type="number" id="message-input-height" value="200"/>
159 148 </div>
160 149 <div class="field box">
161 <label for="recognition-language" class="label" title="">Speech recognition lang</label>
150 <label for="recognition-language" class="label" title="">Speech recognition language</label>
162 151 <input type="text" id="recognition-language" value="" placeholder="navigator.language"/>
163 152 </div>
164 153 <div class="field box">
@@ -250,7 +239,7 @@
250 239 <div class="box input-box">
251 240 <textarea id="message-input" placeholder="Ask a question" cols="30" rows="10"
252 241 style="white-space: pre-wrap;resize: none;"></textarea>
253 <label class="file-label image-label" for="image" title="Works with Bing, Gemini, OpenaiChat and You">
242 <label class="file-label image-label" for="image" title="">
254 243 <input type="file" id="image" name="image" accept="image/*" required/>
255 244 <i class="fa-regular fa-image"></i>
256 245 </label>
@@ -278,12 +267,13 @@
278 267 <option value="gpt-4o">gpt-4o</option>
279 268 <option value="gpt-4o-mini">gpt-4o-mini</option>
280 269 <option value="llama-3.1-70b">llama-3.1-70b</option>
281 <option value="llama-3.1-70b">llama-3.1-405b</option>
282 <option value="llama-3.1-70b">mixtral-8x7b</option>
270 <option value="llama-3.1-405b">llama-3.1-405b</option>
271 <option value="mixtral-8x7b">mixtral-8x7b</option>
283 272 <option value="gemini-pro">gemini-pro</option>
284 273 <option value="gemini-flash">gemini-flash</option>
285 <option value="claude-3-haiku">claude-3-haiku</option>
286 274 <option value="claude-3.5-sonnet">claude-3.5-sonnet</option>
275 <option value="flux">flux (Image Generation)</option>
276 <option value="dall-e-3">dall-e-3 (Image Generation)</option>
287 277 <option disabled="disabled">----</option>
288 278 </select>
289 279 <select name="model2" id="model2" class="hidden"></select>
Modified g4f/gui/client/static/js/chat.v1.js +5 -44
@@ -333,7 +333,7 @@ const handle_ask = async () => {
333 333 }
334 334 messageInput.value = "";
335 335 await count_input()
336 await add_conversation(window.conversation_id, message);
336 await add_conversation(window.conversation_id);
337 337
338 338 if ("text" in fileInput.dataset) {
339 339 message += '\n```' + fileInput.dataset.type + '\n';
@@ -544,20 +544,6 @@ async function add_message_chunk(message, message_id) {
544 544 }
545 545 }
546 546
547 cameraInput?.addEventListener("click", (e) => {
548 if (window?.pywebview) {
549 e.preventDefault();
550 pywebview.api.take_picture();
551 }
552 });
553
554 imageInput?.addEventListener("click", (e) => {
555 if (window?.pywebview) {
556 e.preventDefault();
557 pywebview.api.choose_image();
558 }
559 });
560
561 547 const ask_gpt = async (message_id, message_index = -1, regenerate = false, provider = null, model = null) => {
562 548 if (!model && !provider) {
563 549 model = get_selected_model()?.value || null;
@@ -861,7 +847,7 @@ const load_conversation = async (conversation_id, scroll=true) => {
861 847 if (window.GPTTokenizer_cl100k_base) {
862 848 const filtered = prepare_messages(messages, null);
863 849 if (filtered.length > 0) {
864 last_model = last_model?.startsWith("gpt-4") ? "gpt-4" : "gpt-3.5-turbo"
850 last_model = last_model?.startsWith("gpt-3") ? "gpt-3.5-turbo" : "gpt-4"
865 851 let count_total = GPTTokenizer_cl100k_base?.encodeChat(filtered, last_model).length
866 852 if (count_total > 0) {
867 853 elements += `<div class="count_total">(${count_total} tokens used)</div>`;
@@ -916,7 +902,7 @@ async function get_messages(conversation_id) {
916 902 return conversation?.items || [];
917 903 }
918 904
919 async function add_conversation(conversation_id, content) {
905 async function add_conversation(conversation_id) {
920 906 if (appStorage.getItem(`conversation:${conversation_id}`) == null) {
921 907 await save_conversation(conversation_id, {
922 908 id: conversation_id,
@@ -1134,17 +1120,6 @@ function open_settings() {
1134 1120 log_storage.classList.add("hidden");
1135 1121 }
1136 1122
1137 function open_album() {
1138 if (album.classList.contains("hidden")) {
1139 sidebar.classList.remove("shown");
1140 settings.classList.add("hidden");
1141 album.classList.remove("hidden");
1142 history.pushState({}, null, "/images/");
1143 } else {
1144 album.classList.add("hidden");
1145 }
1146 }
1147
1148 1123 const register_settings_storage = async () => {
1149 1124 const optionElements = document.querySelectorAll(optionElementsSelector);
1150 1125 optionElements.forEach((element) => {
@@ -1277,18 +1252,12 @@ window.addEventListener('load', async function() {
1277 1252 await on_load();
1278 1253 if (window.conversation_id == "{{chat_id}}") {
1279 1254 window.conversation_id = uuid();
1280 } else {
1281 await on_api();
1282 1255 }
1283 });
1284
1285 window.addEventListener('pywebviewready', async function() {
1286 1256 await on_api();
1287 1257 });
1288 1258
1289 1259 async function on_load() {
1290 1260 count_input();
1291
1292 1261 if (/\/chat\/.+/.test(window.location.href)) {
1293 1262 load_conversation(window.conversation_id);
1294 1263 } else {
@@ -1334,7 +1303,7 @@ async function on_api() {
1334 1303 messageInput.addEventListener("keydown", async (evt) => {
1335 1304 if (prompt_lock) return;
1336 1305
1337 // If not mobile
1306 // If not mobile and not shift enter
1338 1307 if (!window.matchMedia("(pointer:coarse)").matches && evt.keyCode === 13 && !evt.shiftKey) {
1339 1308 evt.preventDefault();
1340 1309 console.log("pressed enter");
@@ -1396,6 +1365,7 @@ async function on_api() {
1396 1365 await load_provider_models(appStorage.getItem("provider"));
1397 1366 } catch (e) {
1398 1367 console.error(e)
1368 // Redirect to show basic authenfication
1399 1369 if (document.location.pathname == "/chat/") {
1400 1370 document.location.href = `/chat/error`;
1401 1371 }
@@ -1552,15 +1522,6 @@ function get_selected_model() {
1552 1522 }
1553 1523
1554 1524 async function api(ressource, args=null, file=null, message_id=null) {
1555 if (window?.pywebview) {
1556 if (args !== null) {
1557 if (ressource == "models") {
1558 ressource = "provider_models";
1559 }
1560 return pywebview.api[`get_${ressource}`](args);
1561 }
1562 return pywebview.api[`get_${ressource}`]();
1563 }
1564 1525 let api_key;
1565 1526 if (ressource == "models" && args) {
1566 1527 api_key = get_api_key_by_provider(args);
Modified g4f/gui/client/static/js/highlightjs-copy.min.js +0 -4
Deleted g4f/gui/server/android_gallery.py +0 -67
Deleted g4f/gui/server/js_api.py +0 -94
Modified g4f/gui/webview.py +0 -2
Modified g4f/image.py +1 -2
Modified g4f/models.py +5 -37