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

XFEstudio/gpt4free

Add G4F_PROXY environment Add regenerate button in gui

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

代码差异

6 个文件 +121 -122
Modified README.md +8 -2
@@ -22,7 +22,7 @@ docker pull hlohaus789/g4f
22 22
23 23 ## 📚 Table of Contents
24 24
25 - [🆕 What's New](#-what-s-new)
25 - [🆕 What's New](#-whats-new)
26 26 - [📚 Table of Contents](#-table-of-contents)
27 27 - [🛠️ Getting Started](#-getting-started)
28 28 + [Docker container](#docker-container)
@@ -253,7 +253,7 @@ for message in response:
253 253
254 254 ##### Using Browser
255 255
256 Some providers using a a browser to bypass the bot protection. They using the selenium webdriver to control the browser. The browser settings and the login data are saved in a custom directory. If the headless mode is enabled, the browser windows are loaded invisibly. For performance reasons, it is recommended to reuse the browser instances and close them yourself at the end:
256 Some providers using a browser to bypass the bot protection. They using the selenium webdriver to control the browser. The browser settings and the login data are saved in a custom directory. If the headless mode is enabled, the browser windows are loaded invisibly. For performance reasons, it is recommended to reuse the browser instances and close them yourself at the end:
257 257
258 258 ```python
259 259 import g4f
@@ -335,6 +335,12 @@ response = g4f.ChatCompletion.create(
335 335 print(f"Result:", response)
336 336 ```
337 337
338 You can also set a proxy globally via an environment variable:
339
340 ```sh
341 export G4F_PROXY="http://host:port"
342 ```
343
338 344 ### Interference openai-proxy API (Use with openai python package)
339 345
340 346 #### Run interference API from PyPi package
Modified g4f/__init__.py +5 -1
@@ -96,6 +96,10 @@ class ChatCompletion:
96 96
97 97 if auth:
98 98 kwargs['auth'] = auth
99
100 proxy = os.environ.get("G4F_PROXY")
101 if proxy and "proxy" not in kwargs:
102 kwargs['proxy'] = proxy
99 103
100 104 result = provider.create_completion(model.name, messages, stream, **kwargs)
101 105 return result if stream else ''.join(result)
@@ -112,7 +116,7 @@ class ChatCompletion:
112 116 if stream:
113 117 if isinstance(provider, type) and issubclass(provider, AsyncGeneratorProvider):
114 118 return await provider.create_async_generator(model.name, messages, **kwargs)
115 raise ValueError(f'{provider.__name__} does not support "stream" argument')
119 raise ValueError(f'{provider.__name__} does not support "stream" argument in "create_async"')
116 120
117 121 return await provider.create_async(model.name, messages, **kwargs)
118 122
Modified g4f/gui/client/css/style.css +7 -11
@@ -301,6 +301,9 @@ body {
301 301 font-size: 15px;
302 302 line-height: 1.3;
303 303 }
304 .message .content pre {
305 white-space: pre-wrap;
306 }
304 307
305 308 .message .user i {
306 309 position: absolute;
@@ -338,19 +341,15 @@ body {
338 341 font-size: 14px;
339 342 }
340 343
341
342 .stop_generating {
344 .stop_generating, .regenerate {
343 345 position: absolute;
344 bottom: 118px;
345 /* left: 10px;
346 bottom: 125px;
347 right: 8px; */
346 bottom: 158px;
348 347 left: 50%;
349 348 transform: translateX(-50%);
350 349 z-index: 1000000;
351 350 }
352 351
353 .stop_generating button {
352 .stop_generating button, .regenerate button{
354 353 backdrop-filter: blur(20px);
355 354 -webkit-backdrop-filter: blur(20px);
356 355 background-color: var(--blur-bg);
@@ -380,11 +379,8 @@ body {
380 379 }
381 380 }
382 381
383 .stop_generating-hiding button {
382 .stop_generating-hidden #cancelButton, .regenerate-hidden #regenerateButton {
384 383 animation: hide_popup 0.4s;
385 }
386
387 .stop_generating-hidden button {
388 384 display: none;
389 385 }
390 386
Modified g4f/gui/client/html/index.html +6 -0
@@ -101,6 +101,12 @@
101 101 <i class="fa-regular fa-stop"></i>
102 102 </button>
103 103 </div>
104 <div class="regenerate regenerate-hidden">
105 <button id="regenerateButton">
106 <span>Regenerate</span>
107 <i class="fa-solid fa-rotate"></i>
108 </button>
109 </div>
104 110 <div class="box" id="messages">
105 111 </div>
106 112 <div class="user-input">
Modified g4f/gui/client/js/chat.v1.js +68 -83
@@ -5,15 +5,12 @@ const message_input = document.getElementById(`message-input`);
5 5 const box_conversations = document.querySelector(`.top`);
6 6 const spinner = box_conversations.querySelector(".spinner");
7 7 const stop_generating = document.querySelector(`.stop_generating`);
8 const regenerate = document.querySelector(`.regenerate`);
8 9 const send_button = document.querySelector(`#send-button`);
9 10 let prompt_lock = false;
10 11
11 12 hljs.addPlugin(new CopyButtonPlugin());
12 13
13 const format = (text) => {
14 return text.replace(/(?:\r\n|\r|\n)/g, "<br>");
15 };
16
17 14 message_input.addEventListener("blur", () => {
18 15 window.scrollTo(0, 0);
19 16 });
@@ -22,6 +19,10 @@ message_input.addEventListener("focus", () => {
22 19 document.documentElement.scrollTop = document.documentElement.scrollHeight;
23 20 });
24 21
22 const markdown_render = (content) => {
23 return markdown.render(content).replace("<a href=", '<a target="_blank" href=').replace('<code>', '<code class="language-plaintext">')
24 }
25
25 26 const delete_conversations = async () => {
26 27 localStorage.clear();
27 28 await new_conversation();
@@ -30,38 +31,25 @@ const delete_conversations = async () => {
30 31 const handle_ask = async () => {
31 32 message_input.style.height = `80px`;
32 33 message_input.focus();
33
34 let txtMsgs = [];
35 const divTags = document.getElementsByClassName("message");
36 for(let i=0;i<divTags.length;i++){
37 if(!divTags[i].children[1].classList.contains("welcome-message")){
38 if(divTags[i].children[0].className == "assistant"){
39 const msg = {
40 role: "assistant",
41 content: divTags[i].children[1].textContent+" "
42 };
43 txtMsgs.push(msg);
44 }else{
45 const msg = {
46 role: "user",
47 content: divTags[i].children[1].textContent+" "
48 };
49 txtMsgs.push(msg);
50 }
51 }
52 }
53
54 34 window.scrollTo(0, 0);
55 let message = message_input.value;
56 const msg = {
57 role: "user",
58 content: message
59 };
60 txtMsgs.push(msg);
61
35 message = message_input.value
62 36 if (message.length > 0) {
63 message_input.value = ``;
64 await ask_gpt(txtMsgs);
37 message_input.value = '';
38 await add_conversation(window.conversation_id, message);
39 await add_message(window.conversation_id, "user", message);
40 window.token = message_id();
41 message_box.innerHTML += `
42 <div class="message">
43 <div class="user">
44 ${user_image}
45 <i class="fa-regular fa-phone-arrow-up-right"></i>
46 </div>
47 <div class="content" id="user_${token}">
48 ${markdown_render(message)}
49 </div>
50 </div>
51 `;
52 await ask_gpt();
65 53 }
66 54 };
67 55
@@ -74,13 +62,10 @@ const remove_cancel_button = async () => {
74 62 }, 300);
75 63 };
76 64
77 const ask_gpt = async (txtMsgs) => {
65 const ask_gpt = async () => {
66 regenerate.classList.add(`regenerate-hidden`);
67 messages = await get_messages(window.conversation_id);
78 68 try {
79 message_input.value = ``;
80 message_input.innerHTML = ``;
81 message_input.innerText = ``;
82
83 add_conversation(window.conversation_id, txtMsgs[0].content);
84 69 window.scrollTo(0, 0);
85 70 window.controller = new AbortController();
86 71
@@ -89,22 +74,9 @@ const ask_gpt = async (txtMsgs) => {
89 74 model = document.getElementById("model");
90 75 prompt_lock = true;
91 76 window.text = ``;
92 window.token = message_id();
93 77
94 78 stop_generating.classList.remove(`stop_generating-hidden`);
95 79
96 message_box.innerHTML += `
97 <div class="message">
98 <div class="user">
99 ${user_image}
100 <i class="fa-regular fa-phone-arrow-up-right"></i>
101 </div>
102 <div class="content" id="user_${token}">
103 ${format(txtMsgs[txtMsgs.length-1].content)}
104 </div>
105 </div>
106 `;
107
108 80 message_box.scrollTop = message_box.scrollHeight;
109 81 window.scrollTo(0, 0);
110 82 await new Promise((r) => setTimeout(r, 500));
@@ -138,14 +110,13 @@ const ask_gpt = async (txtMsgs) => {
138 110 action: `_ask`,
139 111 model: model.options[model.selectedIndex].value,
140 112 jailbreak: jailbreak.options[jailbreak.selectedIndex].value,
113 internet_access: document.getElementById(`switch`).checked,
141 114 provider: provider.options[provider.selectedIndex].value,
142 115 meta: {
143 116 id: window.token,
144 117 content: {
145 conversation: await get_conversation(window.conversation_id),
146 internet_access: document.getElementById(`switch`).checked,
147 118 content_type: `text`,
148 parts: txtMsgs,
119 parts: messages,
149 120 },
150 121 },
151 122 }),
@@ -161,7 +132,7 @@ const ask_gpt = async (txtMsgs) => {
161 132
162 133 text += chunk;
163 134
164 document.getElementById(`gpt_${window.token}`).innerHTML = markdown.render(text).replace("<a href=", '<a target="_blank" href=');
135 document.getElementById(`gpt_${window.token}`).innerHTML = markdown_render(text);
165 136 document.querySelectorAll(`code`).forEach((el) => {
166 137 hljs.highlightElement(el);
167 138 });
@@ -171,10 +142,9 @@ const ask_gpt = async (txtMsgs) => {
171 142 }
172 143
173 144 if (text.includes(`G4F_ERROR`)) {
174 document.getElementById(`gpt_${window.token}`).innerHTML = "An error occured, please try again, if the problem persists, please reload / refresh cache or use a differnet browser";
145 document.getElementById(`gpt_${window.token}`).innerHTML = "An error occured, please try again, if the problem persists, please use a other model or provider";
175 146 }
176 147
177 add_message(window.conversation_id, "user", txtMsgs[txtMsgs.length-1].content);
178 148 add_message(window.conversation_id, "assistant", text);
179 149
180 150 message_box.scrollTop = message_box.scrollHeight;
@@ -185,7 +155,6 @@ const ask_gpt = async (txtMsgs) => {
185 155 window.scrollTo(0, 0);
186 156
187 157 } catch (e) {
188 add_message(window.conversation_id, "user", txtMsgs[txtMsgs.length-1].content);
189 158
190 159 message_box.scrollTop = message_box.scrollHeight;
191 160 await remove_cancel_button();
@@ -210,6 +179,7 @@ const ask_gpt = async (txtMsgs) => {
210 179
211 180 window.scrollTo(0, 0);
212 181 }
182 regenerate.classList.remove(`regenerate-hidden`);
213 183 };
214 184
215 185 const clear_conversations = async () => {
@@ -280,7 +250,6 @@ const set_conversation = async (conversation_id) => {
280 250 };
281 251
282 252 const new_conversation = async () => {
283
284 253 history.pushState({}, null, `/chat/`);
285 254 window.conversation_id = uuid();
286 255
@@ -291,12 +260,9 @@ const new_conversation = async () => {
291 260 };
292 261
293 262 const load_conversation = async (conversation_id) => {
294 let conversation = await JSON.parse(
295 localStorage.getItem(`conversation:${conversation_id}`)
296 );
297 console.log(conversation, conversation_id);
263 let messages = await get_messages(conversation_id);
298 264
299 for (item of conversation.items) {
265 for (item of messages) {
300 266 message_box.innerHTML += `
301 267 <div class="message">
302 268 <div class=${item.role == "assistant" ? "assistant" : "user"}>
@@ -308,7 +274,7 @@ const load_conversation = async (conversation_id) => {
308 274 </div>
309 275 <div class="content">
310 276 ${item.role == "assistant"
311 ? markdown.render(item.content).replace("<a href=", '<a target="_blank" href=')
277 ? markdown_render(item.content)
312 278 : item.content
313 279 }
314 280 </div>
@@ -331,6 +297,11 @@ const get_conversation = async (conversation_id) => {
331 297 let conversation = await JSON.parse(
332 298 localStorage.getItem(`conversation:${conversation_id}`)
333 299 );
300 return conversation;
301 };
302
303 const get_messages = async (conversation_id) => {
304 let conversation = await get_conversation(conversation_id);
334 305 return conversation.items;
335 306 };
336 307
@@ -351,21 +322,32 @@ const add_conversation = async (conversation_id, content) => {
351 322 })
352 323 );
353 324 }
325
326 history.pushState({}, null, `/chat/${conversation_id}`);
354 327 };
355 328
356 const add_message = async (conversation_id, role, content) => {
357 before_adding = JSON.parse(
358 localStorage.getItem(`conversation:${conversation_id}`)
329 const remove_last_message = async (conversation_id) => {
330 const conversation = await get_conversation(conversation_id)
331
332 conversation.items.pop();
333
334 localStorage.setItem(
335 `conversation:${conversation_id}`,
336 JSON.stringify(conversation)
359 337 );
338 };
339
340 const add_message = async (conversation_id, role, content) => {
341 const conversation = await get_conversation(conversation_id);
360 342
361 before_adding.items.push({
343 conversation.items.push({
362 344 role: role,
363 345 content: content,
364 346 });
365 347
366 348 localStorage.setItem(
367 349 `conversation:${conversation_id}`,
368 JSON.stringify(before_adding)
350 JSON.stringify(conversation)
369 351 );
370 352 };
371 353
@@ -404,6 +386,12 @@ document.getElementById(`cancelButton`).addEventListener(`click`, async () => {
404 386 console.log(`aborted ${window.conversation_id}`);
405 387 });
406 388
389 document.getElementById(`regenerateButton`).addEventListener(`click`, async () => {
390 await remove_last_message(window.conversation_id);
391 window.token = message_id();
392 await ask_gpt();
393 });
394
407 395 const uuid = () => {
408 396 return `xxxxxxxx-xxxx-4xxx-yxxx-${Date.now().toString(16)}`.replace(
409 397 /[xy]/g,
@@ -485,17 +473,16 @@ const say_hello = async () => {
485 473 ${gpt_image}
486 474 <i class="fa-regular fa-phone-arrow-down-left"></i>
487 475 </div>
488 <div class="content welcome-message">
476 <div class="content">
477 <p class=" welcome-message"></p>
489 478 </div>
490 479 </div>
491 480 `;
492 481
493 content = ``
494 482 to_modify = document.querySelector(`.welcome-message`);
495 483 for (token of tokens) {
496 484 await new Promise(resolve => setTimeout(resolve, (Math.random() * (100 - 200) + 100)))
497 content += token;
498 to_modify.innerHTML = markdown.render(content);
485 to_modify.textContent += token;
499 486 }
500 487 }
501 488
@@ -542,14 +529,12 @@ window.onload = async () => {
542 529 load_conversations(20, 0);
543 530 }, 1);
544 531
545 if (!window.location.href.endsWith(`#`)) {
546 if (/\/chat\/.+/.test(window.location.href)) {
547 await load_conversation(window.conversation_id);
548 }
532 if (/\/chat\/.+/.test(window.location.href)) {
533 await load_conversation(window.conversation_id);
534 } else {
535 await say_hello()
549 536 }
550
551 await say_hello()
552
537
553 538 message_input.addEventListener(`keydown`, async (evt) => {
554 539 if (prompt_lock) return;
555 540 if (evt.keyCode === 13 && !evt.shiftKey) {
Modified g4f/gui/server/backend.py +27 -25
@@ -1,14 +1,15 @@
1 1 import g4f
2 2 from g4f.Provider import __providers__
3 3
4 from flask import request
4 import json
5 from flask import request, Flask
5 6 from .internet import get_search_message
6 7
7 8 g4f.debug.logging = True
8 9
9 10 class Backend_Api:
10 def __init__(self, app) -> None:
11 self.app = app
11 def __init__(self, app: Flask) -> None:
12 self.app: Flask = app
12 13 self.routes = {
13 14 '/backend-api/v2/models': {
14 15 'function': self.models,
@@ -61,19 +62,18 @@ class Backend_Api:
61 62 }
62 63
63 64 def _conversation(self):
64 try:
65 #jailbreak = request.json['jailbreak']
66 web_search = request.json['meta']['content']['internet_access']
67 messages = request.json['meta']['content']['parts']
68 if web_search:
69 messages[-1]["content"] = get_search_message(messages[-1]["content"])
70 model = request.json.get('model')
71 model = model if model else g4f.models.default
72 provider = request.json.get('provider').replace('g4f.Provider.', '')
73 provider = provider if provider and provider != "Auto" else None
74 if provider != None:
75 provider = g4f.Provider.ProviderUtils.convert.get(provider)
76
65 #jailbreak = request.json['jailbreak']
66 messages = request.json['meta']['content']['parts']
67 if request.json['internet_access']:
68 messages[-1]["content"] = get_search_message(messages[-1]["content"])
69 model = request.json.get('model')
70 model = model if model else g4f.models.default
71 provider = request.json.get('provider').replace('g4f.Provider.', '')
72 provider = provider if provider and provider != "Auto" else None
73 if provider != None:
74 provider = g4f.Provider.ProviderUtils.convert.get(provider)
75
76 def try_response():
77 77 response = g4f.ChatCompletion.create(
78 78 model=model,
79 79 provider=provider,
@@ -81,13 +81,15 @@ class Backend_Api:
81 81 stream=True,
82 82 ignore_stream_and_auth=True
83 83 )
84 try:
85 yield from response
86 except Exception as e:
87 print(e)
88 yield json.dumps({
89 'code' : 'G4F_ERROR',
90 '_action': '_ask',
91 'success': False,
92 'error' : f'an error occurred {str(e)}'
93 })
84 94
85 return self.app.response_class(response, mimetype='text/event-stream')
86
87 except Exception as e:
88 print(e)
89 return {
90 'code' : 'G4F_ERROR',
91 '_action': '_ask',
92 'success': False,
93 'error' : f'an error occurred {str(e)}'}, 400
95 return self.app.response_class(try_response(), mimetype='text/event-stream')