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

XFEstudio/gpt4free

Add model preselection in gui

13f1275c
Heiner Lohaus <hlohaus@users.noreply.github.com>
提交于

代码差异

5 个文件 +118 -46
Modified g4f/Provider/Bing.py +18 -13
@@ -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:
Modified g4f/gui/client/css/style.css +4 -0
@@ -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);
Modified g4f/gui/client/html/index.html +4 -0
@@ -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>
Modified g4f/gui/client/js/chat.v1.js +70 -30
@@ -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 = "&nbsp;"
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 = "&nbsp;"
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)
Modified g4f/gui/server/backend.py +22 -3
@@ -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.