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

XFEstudio/gpt4free

Improve model list in HuggingFace WakeLook and disable count tokens for performance Export and import settings in UI Some styling improvments in UI Fix curl_cffi updated bugs

b84f35f4
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

19 个文件 +334 -298
Modified g4f/Provider/Copilot.py +6 -9
@@ -4,11 +4,11 @@ import os
4 4 import json
5 5 import asyncio
6 6 import base64
7 from http.cookiejar import CookieJar
8 7 from urllib.parse import quote
9 8
10 9 try:
11 from curl_cffi.requests import Session, CurlWsFlag
10 from curl_cffi.requests import Session
11 from curl_cffi import CurlWsFlag
12 12 has_curl_cffi = True
13 13 except ImportError:
14 14 has_curl_cffi = False
@@ -55,7 +55,7 @@ class Copilot(AbstractProvider, ProviderModelMixin):
55 55 conversation_url = f"{url}/c/api/conversations"
56 56
57 57 _access_token: str = None
58 _cookies: CookieJar = None
58 _cookies: dict = None
59 59
60 60 @classmethod
61 61 def create_completion(
@@ -86,9 +86,7 @@ class Copilot(AbstractProvider, ProviderModelMixin):
86 86 except NoValidHarFileError as h:
87 87 debug.log(f"Copilot: {h}")
88 88 if has_nodriver:
89 login_url = os.environ.get("G4F_LOGIN_URL")
90 if login_url:
91 yield RequestLogin(cls.label, login_url)
89 yield RequestLogin(cls.label, os.environ.get("G4F_LOGIN_URL", ""))
92 90 get_running_loop(check_nested=True)
93 91 cls._access_token, cls._cookies = asyncio.run(get_access_token_and_cookies(cls.url, proxy))
94 92 else:
@@ -104,7 +102,7 @@ class Copilot(AbstractProvider, ProviderModelMixin):
104 102 cookies=cls._cookies,
105 103 ) as session:
106 104 if cls._access_token is not None:
107 cls._cookies = session.cookies.jar
105 cls._cookies = session.cookies.jar if hasattr(session.cookies, "jar") else session.cookies
108 106 # if cls._access_token is None:
109 107 # try:
110 108 # url = "https://copilot.microsoft.com/cl/eus-sc/collect"
@@ -203,8 +201,7 @@ class Copilot(AbstractProvider, ProviderModelMixin):
203 201 if not is_started:
204 202 raise RuntimeError(f"Invalid response: {last_msg}")
205 203 finally:
206 yield Parameters(**{"conversation": conversation.get_dict(), "user": user, "prompt": prompt})
207 yield Parameters(**{"cookies": {c.name: c.value for c in session.cookies.jar}})
204 wss.close()
208 205
209 206 async def get_access_token_and_cookies(url: str, proxy: str = None, target: str = "ChatAI",):
210 207 browser, stop_browser = await get_nodriver(proxy=proxy, user_data_dir="copilot")
Modified g4f/Provider/PollinationsImage.py +5 -4
@@ -7,16 +7,17 @@ from ..typing import AsyncResult, Messages
7 7 from .PollinationsAI import PollinationsAI
8 8
9 9 class PollinationsImage(PollinationsAI):
10 label = "Pollinations AI (Image)"
11 10 default_model = "flux"
12 11 default_vision_model = None
13 12 default_image_model = default_model
13 image_models = [default_image_model]
14 14
15 15 @classmethod
16 16 def get_models(cls, **kwargs):
17 if not cls.image_models:
18 cls.image_models = list(dict.fromkeys([*cls.image_models, *cls.extra_image_models]))
19 return cls.image_models
17 if not cls.models:
18 super().get_models(**kwargs)
19 cls.models = cls.image_models
20 return cls.models
20 21
21 22 @classmethod
22 23 async def create_async_generator(
Modified g4f/Provider/__init__.py +1 -2
@@ -10,7 +10,7 @@ from .needs_auth import *
10 10 from .not_working import *
11 11 from .local import *
12 12 from .hf import HuggingFace, HuggingChat, HuggingFaceAPI, HuggingFaceInference
13 from .hf_space import HuggingSpace
13 from .hf_space import *
14 14 from .mini_max import HailuoAI, MiniMax
15 15 from .template import OpenaiTemplate, BackendApi
16 16
@@ -53,7 +53,6 @@ __providers__: list[ProviderType] = [
53 53 if isinstance(provider, type)
54 54 and issubclass(provider, BaseProvider)
55 55 ]
56 __providers__ = __providers__ + HuggingSpace.providers
57 56 __all__: list[str] = [
58 57 provider.__name__ for provider in __providers__
59 58 ]
Modified g4f/Provider/hf/HuggingFaceInference.py +7 -7
@@ -11,7 +11,7 @@ from ...errors import ModelNotSupportedError, ResponseError
11 11 from ...requests import StreamSession, raise_for_status
12 12 from ...providers.response import FinishReason, ImageResponse
13 13 from ..helper import format_image_prompt, get_last_user_message
14 from .models import default_model, default_image_model, model_aliases, fallback_models, image_models
14 from .models import default_model, default_image_model, model_aliases, text_models, image_models, vision_models
15 15 from ... import debug
16 16
17 17 class HuggingFaceInference(AsyncGeneratorProvider, ProviderModelMixin):
@@ -29,18 +29,18 @@ class HuggingFaceInference(AsyncGeneratorProvider, ProviderModelMixin):
29 29 @classmethod
30 30 def get_models(cls) -> list[str]:
31 31 if not cls.models:
32 models = fallback_models.copy()
32 models = text_models.copy()
33 33 url = "https://huggingface.co/api/models?inference=warm&pipeline_tag=text-generation"
34 34 response = requests.get(url)
35 35 if response.ok:
36 extra_models = [model["id"] for model in response.json()]
37 extra_models.sort()
38 models.extend([model for model in extra_models if model not in models])
36 extra_models = [model["id"] for model in response.json() if model.get("trendingScore", 0) >= 10]
37 models = extra_models + vision_models + [model for model in models if model not in extra_models]
39 38 url = "https://huggingface.co/api/models?pipeline_tag=text-to-image"
40 39 response = requests.get(url)
40 cls.image_models = image_models.copy()
41 41 if response.ok:
42 cls.image_models = [model["id"] for model in response.json() if model.get("trendingScore", 0) >= 20]
43 cls.image_models.sort()
42 extra_models = [model["id"] for model in response.json() if model.get("trendingScore", 0) >= 20]
43 cls.image_models.extend([model for model in extra_models if model not in cls.image_models])
44 44 models.extend([model for model in cls.image_models if model not in models])
45 45 cls.models = models
46 46 return cls.models
Modified g4f/Provider/hf/models.py +3 -2
@@ -4,7 +4,7 @@ image_models = [
4 4 default_image_model,
5 5 "black-forest-labs/FLUX.1-schnell",
6 6 ]
7 fallback_models = [
7 text_models = [
8 8 default_model,
9 9 'meta-llama/Llama-3.3-70B-Instruct',
10 10 'CohereForAI/c4ai-command-r-plus-08-2024',
@@ -15,7 +15,8 @@ fallback_models = [
15 15 'meta-llama/Llama-3.2-11B-Vision-Instruct',
16 16 'mistralai/Mistral-Nemo-Instruct-2407',
17 17 'microsoft/Phi-3.5-mini-instruct',
18 ] + image_models
18 ]
19 fallback_models = text_models + image_models
19 20 model_aliases = {
20 21 ### Chat ###
21 22 "qwen-2.5-72b": "Qwen/Qwen2.5-Coder-32B-Instruct",
Modified g4f/Provider/hf_space/BlackForestLabsFlux1Dev.py +2 -2
@@ -62,7 +62,7 @@ class BlackForestLabsFlux1Dev(AsyncGeneratorProvider, ProviderModelMixin):
62 62 seed: int = 0,
63 63 randomize_seed: bool = True,
64 64 cookies: dict = None,
65 zerogpu_token: str = None,
65 api_key: str = None,
66 66 zerogpu_uuid: str = "[object Object]",
67 67 **kwargs
68 68 ) -> AsyncResult:
@@ -70,7 +70,7 @@ class BlackForestLabsFlux1Dev(AsyncGeneratorProvider, ProviderModelMixin):
70 70 async with StreamSession(impersonate="chrome", proxy=proxy) as session:
71 71 prompt = format_image_prompt(messages, prompt)
72 72 data = [prompt, seed, randomize_seed, width, height, guidance_scale, num_inference_steps]
73 conversation = JsonConversation(zerogpu_token=zerogpu_token, zerogpu_uuid=zerogpu_uuid, session_hash=uuid.uuid4().hex)
73 conversation = JsonConversation(zerogpu_token=api_key, zerogpu_uuid=zerogpu_uuid, session_hash=uuid.uuid4().hex)
74 74 if conversation.zerogpu_token is None:
75 75 conversation.zerogpu_uuid, conversation.zerogpu_token = await get_zerogpu_token(cls.space, session, conversation, cookies)
76 76 async with cls.run(f"post", session, conversation, data) as response:
Modified g4f/Provider/hf_space/G4F.py +8 -7
@@ -2,6 +2,7 @@ from __future__ import annotations
2 2
3 3 from aiohttp import ClientSession
4 4 import time
5 import random
5 6 import asyncio
6 7
7 8 from ...typing import AsyncResult, Messages
@@ -40,7 +41,7 @@ class G4F(Janus_Pro_7B):
40 41 height: int = 1024,
41 42 seed: int = None,
42 43 cookies: dict = None,
43 zerogpu_token: str = None,
44 api_key: str = None,
44 45 zerogpu_uuid: str = "[object Object]",
45 46 **kwargs
46 47 ) -> AsyncResult:
@@ -53,7 +54,7 @@ class G4F(Janus_Pro_7B):
53 54 height=height,
54 55 seed=seed,
55 56 cookies=cookies,
56 zerogpu_token=zerogpu_token,
57 api_key=api_key,
57 58 zerogpu_uuid=zerogpu_uuid,
58 59 **kwargs
59 60 ):
@@ -66,7 +67,7 @@ class G4F(Janus_Pro_7B):
66 67 prompt=prompt,
67 68 seed=seed,
68 69 cookies=cookies,
69 zerogpu_token=zerogpu_token,
70 api_key=api_key,
70 71 zerogpu_uuid=zerogpu_uuid,
71 72 **kwargs
72 73 ):
@@ -79,7 +80,7 @@ class G4F(Janus_Pro_7B):
79 80 if prompt is None:
80 81 prompt = format_image_prompt(messages)
81 82 if seed is None:
82 seed = int(time.time())
83 seed = random.randint(9999, 2**32 - 1)
83 84
84 85 payload = {
85 86 "data": [
@@ -96,11 +97,11 @@ class G4F(Janus_Pro_7B):
96 97 "trigger_id": 10
97 98 }
98 99 async with ClientSession() as session:
99 if zerogpu_token is None:
100 if api_key is None:
100 101 yield Reasoning(status="Acquiring GPU Token")
101 zerogpu_uuid, zerogpu_token = await get_zerogpu_token(cls.space, session, JsonConversation(), cookies)
102 zerogpu_uuid, api_key = await get_zerogpu_token(cls.space, session, JsonConversation(), cookies)
102 103 headers = {
103 "x-zerogpu-token": zerogpu_token,
104 "x-zerogpu-token": api_key,
104 105 "x-zerogpu-uuid": zerogpu_uuid,
105 106 }
106 107 headers = {k: v for k, v in headers.items() if v is not None}
Modified g4f/Provider/hf_space/Janus_Pro_7B.py +7 -11
@@ -71,17 +71,13 @@ class Janus_Pro_7B(AsyncGeneratorProvider, ProviderModelMixin):
71 71 prompt: str = None,
72 72 proxy: str = None,
73 73 cookies: Cookies = None,
74 zerogpu_token: str = None,
74 api_key: str = None,
75 75 zerogpu_uuid: str = "[object Object]",
76 76 return_conversation: bool = False,
77 77 conversation: JsonConversation = None,
78 78 seed: int = None,
79 79 **kwargs
80 80 ) -> AsyncResult:
81 def generate_session_hash():
82 """Generate a unique session hash."""
83 return str(uuid.uuid4()).replace('-', '')[:12]
84
85 81 method = "post"
86 82 if model == cls.default_image_model or prompt is not None:
87 83 method = "image"
@@ -90,14 +86,14 @@ class Janus_Pro_7B(AsyncGeneratorProvider, ProviderModelMixin):
90 86 if seed is None:
91 87 seed = random.randint(1000, 999999)
92 88
93 session_hash = generate_session_hash() if conversation is None else getattr(conversation, "session_hash")
89 session_hash = uuid.uuid4().hex if conversation is None else getattr(conversation, "session_hash", uuid.uuid4().hex)
94 90 async with StreamSession(proxy=proxy, impersonate="chrome") as session:
95 session_hash = generate_session_hash() if conversation is None else getattr(conversation, "session_hash")
96 if zerogpu_token is None:
97 zerogpu_uuid, zerogpu_token = await get_zerogpu_token(cls.space, session, conversation, cookies)
91 if api_key is None:
92 zerogpu_uuid, api_key = await get_zerogpu_token(cls.space, session, conversation, cookies)
98 93 if conversation is None or not hasattr(conversation, "session_hash"):
99 conversation = JsonConversation(session_hash=session_hash, zerogpu_token=zerogpu_token, zerogpu_uuid=zerogpu_uuid)
100 conversation.zerogpu_token = zerogpu_token
94 conversation = JsonConversation(session_hash=session_hash, zerogpu_token=api_key, zerogpu_uuid=zerogpu_uuid)
95 else:
96 conversation.zerogpu_token = api_key
101 97 if return_conversation:
102 98 yield conversation
103 99
Modified g4f/gui/client/demo.html +12 -4
@@ -183,13 +183,21 @@
183 183 const isIframe = window.self !== window.top;
184 184 const backendUrl = "{{backend_url}}";
185 185 let url = new URL(window.location.href)
186 let params = new URLSearchParams(url.search);
186 187 if (isIframe && backendUrl) {
187 window.location.replace(url.search ? `${backendUrl}?${url.search}` : backendUrl);
188 if (params.get("get_gpu_token")) {
189 window.addEventListener('DOMContentLoaded', async function() {
190 const link = document.getElementById("new_window");
191 link.href = `${backendUrl}${url.search}`;
192 link.click();
193 });
194 } else {
195 window.location.replace(`${backendUrl}${url.search}`);
196 }
188 197 return;
189 198 }
190 let params = new URLSearchParams(url.search);
191 199 if (params.get("__sign")) {
192 localStorage.setItem("zerogpu_token", params.get("__sign"));
200 localStorage.setItem("HuggingSpace-api_key", params.get("__sign"));
193 201 if (!isIframe) {
194 202 window.location.replace("/");
195 203 }
@@ -226,7 +234,7 @@
226 234 <form action="/chat/">
227 235 <input type="text" name="token" class="input-field" placeholder="Enter an Access Token..." autocomplete="off">
228 236 <div class="button-container">
229 <a href="" class="button hidden" target="_blank">New Window</a>
237 <a id="new_window" href="" class="button hidden" target="_blank">New Window</a>
230 238 <button class="button">Submit</button>
231 239 </div>
232 240 <p>
Modified g4f/gui/client/home.html +4 -4
@@ -224,15 +224,15 @@
224 224 </div>
225 225 <script>
226 226 const iframe = document.querySelector('.stream-widget');
227 const rand_idx = Math.floor(Math.random() * 9)
227 const rand_idx = Math.floor(Math.random() * 12)
228 228 if (rand_idx < 3) {
229 229 search = "xtekky/gpt4free releases";
230 } else if (rand_idx < 5) {
230 } else if (rand_idx < 6) {
231 231 search = "developer news";
232 232 } else {
233 233 search = (navigator.language == "de" ? "news in deutsch" : navigator.language == "en" ? "world news" : `news in ${navigator.language}`);
234 234 }
235 const summary_prompt = "Give a summary of the provided text in ```markdown``` format. Add maybe one or more images.";
235 const summary_prompt = "Present the news from the search results in a clear and organized markdown format. Include a headline, a brief summary, key points, and one or more relevant images with proper attribution. Ensure the content is concise, well-structured, and visually appealing.";
236 236 const url = `/backend-api/v2/create?prompt=${summary_prompt}&stream=1&web_search=${search}`;
237 237 iframe.src = url;
238 238 const message = "Loading...";
@@ -265,7 +265,7 @@
265 265 if (!i.contentWindow || !i.contentDocument) {
266 266 return;
267 267 }
268 clientHeight = i.contentDocument.body.scrollHeight;
268 clientHeight = i.contentDocument.body?.scrollHeight;
269 269 i.contentWindow.scrollTo(0, clientHeight);
270 270 if (clientHeight - i.contentWindow.scrollY < 2 * clientHeight) {
271 271 setTimeout(scroll_to_bottom_callback, 1000);
Modified g4f/gui/client/index.html +25 -8
@@ -33,14 +33,22 @@
33 33 };
34 34 </script>
35 35 <script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" async></script>
36 <script type="module" src="https://cdn.jsdelivr.net/npm/mistral-tokenizer-js" async>
37 import mistralTokenizer from "mistral-tokenizer-js"
38 </script>
39 <script type="module" src="https://cdn.jsdelivr.net/gh/belladoreai/llama-tokenizer-js@master/llama-tokenizer.js" async>
40 import llamaTokenizer from "llama-tokenizer-js"
36 <template>
37 <script type="module" src="https://cdn.jsdelivr.net/npm/mistral-tokenizer-js" async>
38 import mistralTokenizer from "mistral-tokenizer-js"
39 </script>
40 <script type="module" src="https://cdn.jsdelivr.net/gh/belladoreai/llama-tokenizer-js@master/llama-tokenizer.js" async>
41 import llamaTokenizer from "llama-tokenizer-js"
42 </script>
43 <script src="https://cdn.jsdelivr.net/npm/gpt-tokenizer/dist/cl100k_base.js" async></script>
44 <script src="https://cdn.jsdelivr.net/npm/gpt-tokenizer/dist/o200k_base.js" async></script>
45 </template>
46 <script>
47 if (localStorage.getItem("countTokens") != "false") {
48 const template = document.head.querySelector('template');
49 document.head.appendChild(template.content);
50 }
41 51 </script>
42 <script src="https://cdn.jsdelivr.net/npm/gpt-tokenizer/dist/cl100k_base.js" async></script>
43 <script src="https://cdn.jsdelivr.net/npm/gpt-tokenizer/dist/o200k_base.js" async></script>
44 52 <script type="module" async>
45 53 import PhotoSwipeLightbox from 'https://cdn.jsdelivr.net/npm/photoswipe/dist/photoswipe-lightbox.esm.js';
46 54 const lightbox = new PhotoSwipeLightbox({
@@ -168,6 +176,11 @@
168 176 <input type="checkbox" id="report_error" checked/>
169 177 <label for="report_error" class="toogle" title=""></label>
170 178 </div>
179 <div class="field">
180 <span class="label">Count words and tokens</span>
181 <input type="checkbox" id="countTokens" checked/>
182 <label for="countTokens" class="toogle" title=""></label>
183 </div>
171 184 <div class="field box">
172 185 <label for="systemPrompt" class="label">System prompt</label>
173 186 <textarea id="systemPrompt" placeholder="You are a helpful assistant." data-example="If you need to generate images, you can use the following format: ![keywords](/generate/filename.jpg). This will enable the use of an image generation tool."></textarea>
@@ -193,7 +206,7 @@
193 206 <label for="mem0-api_key" class="label" title="">Mem0 API:</label>
194 207 <input type="text" id="mem0-api_key" name="mem0[api_key]" placeholder="api_key"/>
195 208 </div>
196 <div class="field box">
209 <div class="field box hidden">
197 210 <label for="Custom-api_base" class="label" title="">Custom Provider (Base Url):</label>
198 211 <input type="text" id="Custom-api_base" name="Custom[api_base]" placeholder="http://localhost:8080/v1"/>
199 212 </div>
@@ -215,6 +228,10 @@
215 228 <i class="fa-solid fa-download"></i>
216 229 <a href="" onclick="return false;">Export Conversations</a>
217 230 </button>
231 <button onclick="save_storage(true)">
232 <i class="fa-solid fa-pencil"></i>
233 <a href="" onclick="return false;">Export Settings</a>
234 </button>
218 235 <button id="showLog">
219 236 <i class="fa-solid fa-terminal"></i>
220 237 <a href="" onclick="return false;">Show log</a>
Modified g4f/gui/client/static/css/style.css +7 -7
@@ -768,11 +768,10 @@ form input:checked+label {
768 768 }
769 769
770 770 .settings .bottom_buttons {
771 flex-direction: column;
771 padding-bottom: 50px;
772 772 }
773 773
774 774 .settings .bottom_buttons button {
775 display: inline-block;
776 775 max-width: 210px;
777 776 width: 100%;
778 777 }
@@ -858,6 +857,10 @@ button.regenerate_button, button.continue_button, button.options_button {
858 857 backdrop-filter: none;
859 858 }
860 859
860 button.options_button {
861 margin-left: auto;
862 }
863
861 864 .buttons button.pinned span {
862 865 max-width: 160px;
863 866 overflow: hidden;
@@ -1026,6 +1029,7 @@ input.model:hover
1026 1029 .mem0 button span {
1027 1030 color: var(--colour-3);
1028 1031 font-weight: 500;
1032 text-decoration: none;
1029 1033 }
1030 1034
1031 1035 .conversations .top {
@@ -1145,7 +1149,7 @@ ul {
1145 1149 }
1146 1150
1147 1151 .settings h3 {
1148 padding-left: 54px;
1152 padding-left: 14px;
1149 1153 padding-top: 18px;
1150 1154 }
1151 1155
@@ -1164,10 +1168,6 @@ ul {
1164 1168 padding-left: 60px;
1165 1169 }
1166 1170
1167 .settings h3 {
1168 text-align: center;
1169 }
1170
1171 1171 .field.collapsible {
1172 1172 flex-direction: column;
1173 1173 }
Modified g4f/gui/client/static/img/site.webmanifest +1 -0
Modified g4f/gui/client/static/js/chat.v1.js +221 -215
Modified g4f/gui/server/backend_api.py +1 -3
Modified g4f/models.py +12 -5
Modified g4f/providers/base_provider.py +5 -5
Modified g4f/requests/__init__.py +6 -2
Modified g4f/tools/web_search.py +1 -1