返回提交历史
Modified
g4f/Provider/Bing.py
+18
-13
Modified
g4f/gui/client/css/style.css
+4
-0
Modified
g4f/gui/client/html/index.html
+4
-0
Modified
g4f/gui/client/js/chat.v1.js
+70
-30
Modified
g4f/gui/server/backend.py
+22
-3
XFEstudio/gpt4free
Add model preselection in gui
13f1275c
代码差异
5 个文件
+118
-46
@@ -12,7 +12,7 @@ from aiohttp import ClientSession, ClientTimeout, BaseConnector, WSMsgType
12
12
from ..typing import AsyncResult, Messages, ImageType, Cookies
13
13
from ..image import ImageRequest
14
14
from ..errors import ResponseStatusError
15
from .base_provider import AsyncGeneratorProvider
15
from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
16
16
from .helper import get_connector, get_random_hex
17
17
from .bing.upload_image import upload_image
18
18
from .bing.conversation import Conversation, create_conversation, delete_conversation
@@ -27,7 +27,7 @@ class Tones:
27
27
balanced = "Balanced"
28
28
precise = "Precise"
29
29
30
class Bing(AsyncGeneratorProvider):
30
class Bing(AsyncGeneratorProvider, ProviderModelMixin):
31
31
"""
32
32
Bing provider for generating responses using the Bing API.
33
33
"""
@@ -35,16 +35,21 @@ class Bing(AsyncGeneratorProvider):
35
35
working = True
36
36
supports_message_history = True
37
37
supports_gpt_4 = True
38
default_model = Tones.balanced
39
models = [
40
getattr(Tones, key) for key in dir(Tones) if not key.startswith("__")
41
]
38
42
39
@staticmethod
43
@classmethod
40
44
def create_async_generator(
45
cls,
41
46
model: str,
42
47
messages: Messages,
43
48
proxy: str = None,
44
49
timeout: int = 900,
45
50
cookies: Cookies = None,
46
51
connector: BaseConnector = None,
47
tone: str = Tones.balanced,
52
tone: str = None,
48
53
image: ImageType = None,
49
54
web_search: bool = False,
50
55
**kwargs
@@ -62,13 +67,11 @@ class Bing(AsyncGeneratorProvider):
62
67
:param web_search: Flag to enable or disable web search.
63
68
:return: An asynchronous result object.
64
69
"""
65
if len(messages) < 2:
66
prompt = messages[0]["content"]
67
context = None
68
else:
69
prompt = messages[-1]["content"]
70
context = create_context(messages[:-1])
71
70
prompt = messages[-1]["content"]
71
context = create_context(messages[:-1]) if len(messages) > 1 else None
72
if tone is None:
73
tone = tone if model.startswith("gpt-4") else model
74
tone = cls.get_model(tone)
72
75
gpt4_turbo = True if model.startswith("gpt-4-turbo") else False
73
76
74
77
return stream_generate(
@@ -86,7 +89,9 @@ def create_context(messages: Messages) -> str:
86
89
:return: A string representing the context created from the messages.
87
90
"""
88
91
return "".join(
89
f"[{message['role']}]" + ("(#message)" if message['role'] != "system" else "(#additional_instructions)") + f"\n{message['content']}"
92
f"[{message['role']}]" + ("(#message)"
93
if message['role'] != "system"
94
else "(#additional_instructions)") + f"\n{message['content']}"
90
95
for message in messages
91
96
) + "\n\n"
92
97
@@ -403,7 +408,7 @@ async def stream_generate(
403
408
do_read = False
404
409
if response_txt.startswith(returned_text):
405
410
new = response_txt[len(returned_text):]
406
if new != "\n":
411
if new not in ("", "\n"):
407
412
yield new
408
413
returned_text = response_txt
409
414
if image_response:
@@ -106,6 +106,10 @@ body {
106
106
border: 1px solid var(--blur-border);
107
107
}
108
108
109
.hidden {
110
display: none;
111
}
112
109
113
.conversations {
110
114
max-width: 260px;
111
115
padding: var(--section-gap);
@@ -162,6 +162,10 @@
162
162
<option value="">----</option>
163
163
</select>
164
164
</div>
165
<div class="field">
166
<select name="model2" id="model2" class="hidden">
167
</select>
168
</div>
165
169
<div class="field">
166
170
<select name="jailbreak" id="jailbreak" style="display: none;">
167
171
<option value="default" selected>Set Jailbreak</option>
@@ -12,7 +12,9 @@ const imageInput = document.getElementById("image");
12
12
const cameraInput = document.getElementById("camera");
13
13
const fileInput = document.getElementById("file");
14
14
const inputCount = document.getElementById("input-count")
15
const providerSelect = document.getElementById("provider");
15
16
const modelSelect = document.getElementById("model");
17
const modelProvider = document.getElementById("model2");
16
18
const systemPrompt = document.getElementById("systemPrompt")
17
19
18
20
let prompt_lock = false;
@@ -44,17 +46,21 @@ const markdown_render = (content) => {
44
46
}
45
47
46
48
let typesetPromise = Promise.resolve();
49
let timeoutHighlightId;
47
50
const highlight = (container) => {
48
container.querySelectorAll('code:not(.hljs').forEach((el) => {
49
if (el.className != "hljs") {
50
hljs.highlightElement(el);
51
}
52
});
53
typesetPromise = typesetPromise.then(
54
() => MathJax.typesetPromise([container])
55
).catch(
56
(err) => console.log('Typeset failed: ' + err.message)
57
);
51
if (timeoutHighlightId) clearTimeout(timeoutHighlightId);
52
timeoutHighlightId = setTimeout(() => {
53
container.querySelectorAll('code:not(.hljs').forEach((el) => {
54
if (el.className != "hljs") {
55
hljs.highlightElement(el);
56
}
57
});
58
typesetPromise = typesetPromise.then(
59
() => MathJax.typesetPromise([container])
60
).catch(
61
(err) => console.log('Typeset failed: ' + err.message)
62
);
63
}, 100);
58
64
}
59
65
60
66
const register_remove_message = async () => {
@@ -108,7 +114,6 @@ const handle_ask = async () => {
108
114
if (input.files.length > 0) imageInput.dataset.src = URL.createObjectURL(input.files[0]);
109
115
else delete imageInput.dataset.src
110
116
111
model = modelSelect.options[modelSelect.selectedIndex].value
112
117
message_box.innerHTML += `
113
118
<div class="message" data-index="${message_index}">
114
119
<div class="user">
@@ -124,7 +129,7 @@ const handle_ask = async () => {
124
129
: ''
125
130
}
126
131
</div>
127
<div class="count">${count_words_and_tokens(message, model)}</div>
132
<div class="count">${count_words_and_tokens(message, get_selected_model())}</div>
128
133
</div>
129
134
</div>
130
135
`;
@@ -204,7 +209,6 @@ const ask_gpt = async () => {
204
209
window.controller = new AbortController();
205
210
206
211
jailbreak = document.getElementById("jailbreak");
207
provider = document.getElementById("provider");
208
212
window.text = '';
209
213
210
214
stop_generating.classList.remove(`stop_generating-hidden`);
@@ -241,10 +245,10 @@ const ask_gpt = async () => {
241
245
let body = JSON.stringify({
242
246
id: window.token,
243
247
conversation_id: window.conversation_id,
244
model: modelSelect.options[modelSelect.selectedIndex].value,
248
model: get_selected_model(),
245
249
jailbreak: jailbreak.options[jailbreak.selectedIndex].value,
246
250
web_search: document.getElementById(`switch`).checked,
247
provider: provider.options[provider.selectedIndex].value,
251
provider: providerSelect.options[providerSelect.selectedIndex].value,
248
252
patch_provider: document.getElementById('patch')?.checked,
249
253
messages: messages
250
254
});
@@ -666,11 +670,13 @@ sidebar_button.addEventListener("click", (event) => {
666
670
window.scrollTo(0, 0);
667
671
});
668
672
673
const options = ["switch", "model", "model2", "jailbreak", "patch", "provider", "history"];
674
669
675
const register_settings_localstorage = async () => {
670
for (id of ["switch", "model", "jailbreak", "patch", "provider", "history"]) {
676
options.forEach((id) => {
671
677
element = document.getElementById(id);
672
678
if (!element) {
673
continue;
679
return;
674
680
}
675
681
element.addEventListener('change', async (event) => {
676
682
switch (event.target.type) {
@@ -684,14 +690,14 @@ const register_settings_localstorage = async () => {
684
690
console.warn("Unresolved element type");
685
691
}
686
692
});
687
}
693
});
688
694
}
689
695
690
696
const load_settings_localstorage = async () => {
691
for (id of ["switch", "model", "jailbreak", "patch", "provider", "history"]) {
697
options.forEach((id) => {
692
698
element = document.getElementById(id);
693
699
if (!element || !(value = appStorage.getItem(element.id))) {
694
continue;
700
return;
695
701
}
696
702
if (value) {
697
703
switch (element.type) {
@@ -705,7 +711,7 @@ const load_settings_localstorage = async () => {
705
711
console.warn("Unresolved element type");
706
712
}
707
713
}
708
}
714
});
709
715
}
710
716
711
717
const say_hello = async () => {
@@ -780,13 +786,16 @@ function count_words_and_tokens(text, model) {
780
786
}
781
787
782
788
let countFocus = messageInput;
789
let timeoutId;
783
790
const count_input = async () => {
784
if (countFocus.value) {
785
model = modelSelect.options[modelSelect.selectedIndex].value;
786
inputCount.innerText = count_words_and_tokens(countFocus.value, model);
787
} else {
788
inputCount.innerHTML = " "
789
}
791
if (timeoutId) clearTimeout(timeoutId);
792
timeoutId = setTimeout(() => {
793
if (countFocus.value) {
794
inputCount.innerText = count_words_and_tokens(countFocus.value, get_selected_model());
795
} else {
796
inputCount.innerHTML = " "
797
}
798
}, 100);
790
799
};
791
800
messageInput.addEventListener("keyup", count_input);
792
801
systemPrompt.addEventListener("keyup", count_input);
@@ -850,11 +859,13 @@ window.onload = async () => {
850
859
providers = await response.json()
851
860
select = document.getElementById('provider');
852
861
853
for (provider of providers) {
862
providers.forEach((provider) => {
854
863
let option = document.createElement('option');
855
864
option.value = option.text = provider;
856
865
select.appendChild(option);
857
}
866
})
867
868
await load_provider_models();
858
869
859
870
await load_settings_localstorage()
860
871
})();
@@ -914,4 +925,33 @@ fileInput.addEventListener('change', async (event) => {
914
925
915
926
systemPrompt?.addEventListener("blur", async () => {
916
927
await save_system_message();
917
});
928
});
929
930
function get_selected_model() {
931
if (modelProvider.selectedIndex >= 0) {
932
return modelProvider.options[modelProvider.selectedIndex].value;
933
} else if (modelSelect.selectedIndex >= 0) {
934
return modelSelect.options[modelSelect.selectedIndex].value;
935
}
936
}
937
938
async function load_provider_models() {
939
provider = providerSelect.options[providerSelect.selectedIndex].value;
940
response = await fetch('/backend-api/v2/models/' + provider);
941
models = await response.json();
942
if (models.length > 0) {
943
modelSelect.classList.add("hidden");
944
modelProvider.classList.remove("hidden");
945
modelProvider.innerHTML = '';
946
models.forEach((model) => {
947
let option = document.createElement('option');
948
option.value = option.text = model.model;
949
option.selected = model.default;
950
modelProvider.appendChild(option);
951
});
952
} else {
953
modelProvider.classList.add("hidden");
954
modelSelect.classList.remove("hidden");
955
}
956
};
957
providerSelect.addEventListener("change", load_provider_models)
@@ -6,10 +6,11 @@ from g4f import version, models
6
6
from g4f import get_last_provider, ChatCompletion
7
7
from g4f.image import is_allowed_extension, to_image
8
8
from g4f.errors import VersionNotFoundError
9
from g4f.Provider import __providers__
9
from g4f.Provider import ProviderType, __providers__, __map__
10
from g4f.providers.base_provider import ProviderModelMixin
10
11
from g4f.Provider.bing.create_images import patch_provider
11
12
12
class Backend_Api:
13
class Backend_Api:
13
14
"""
14
15
Handles various endpoints in a Flask application for backend operations.
15
16
@@ -33,6 +34,10 @@ class Backend_Api:
33
34
'function': self.get_models,
34
35
'methods': ['GET']
35
36
},
37
'/backend-api/v2/models/<provider>': {
38
'function': self.get_provider_models,
39
'methods': ['GET']
40
},
36
41
'/backend-api/v2/providers': {
37
42
'function': self.get_providers,
38
43
'methods': ['GET']
@@ -75,7 +80,21 @@ class Backend_Api:
75
80
List[str]: A list of model names.
76
81
"""
77
82
return models._all_models
78
83
84
def get_provider_models(self, provider: str):
85
if provider in __map__:
86
provider: ProviderType = __map__[provider]
87
if issubclass(provider, ProviderModelMixin):
88
return [{"model": model, "default": model == provider.default_model} for model in provider.get_models()]
89
elif provider.supports_gpt_35_turbo or provider.supports_gpt_4:
90
return [
91
*([{"model": "gpt-3.5-turbo", "default": not provider.supports_gpt_4}] if provider.supports_gpt_35_turbo else []),
92
*([{"model": "gpt-4", "default": not provider.supports_gpt_4}] if provider.supports_gpt_4 else [])
93
]
94
else:
95
return [];
96
return 404, "Provider not found"
97
79
98
def get_providers(self):
80
99
"""
81
100
Return a list of all working providers.