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

XFEstudio/gpt4free

Add show log option to gui

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

代码差异

10 个文件 +96 -46
Modified g4f/Provider/Copilot.py +3 -6
@@ -93,13 +93,11 @@ class Copilot(AbstractProvider):
93 93 if return_conversation:
94 94 yield Conversation(conversation_id, session.cookies.jar, access_token)
95 95 prompt = format_prompt(messages)
96 if debug.logging:
97 print(f"Copilot: Created conversation: {conversation_id}")
96 debug.log(f"Copilot: Created conversation: {conversation_id}")
98 97 else:
99 98 conversation_id = conversation.conversation_id
100 99 prompt = messages[-1]["content"]
101 if debug.logging:
102 print(f"Copilot: Use conversation: {conversation_id}")
100 debug.log(f"Copilot: Use conversation: {conversation_id}")
103 101
104 102 images = []
105 103 if image is not None:
@@ -143,8 +141,7 @@ class Copilot(AbstractProvider):
143 141 if not has_nodriver:
144 142 raise MissingRequirementsError('Install "nodriver" package | pip install -U nodriver')
145 143 user_data_dir = user_config_dir("g4f-nodriver") if has_platformdirs else None
146 if debug.logging:
147 print(f"Copilot: Open nodriver with user_dir: {user_data_dir}")
144 debug.log(f"Copilot: Open nodriver with user_dir: {user_data_dir}")
148 145 browser = await nodriver.start(
149 146 user_data_dir=user_data_dir,
150 147 browser_args=None if proxy is None else [f"--proxy-server={proxy}"],
Modified g4f/Provider/needs_auth/OpenaiChat.py +35 -28
@@ -282,8 +282,11 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
282 282 Raises:
283 283 RuntimeError: If there'san error in downloading the image, including issues with the HTTP request or response.
284 284 """
285 prompt = element["metadata"]["dalle"]["prompt"]
286 file_id = element["asset_pointer"].split("file-service://", 1)[1]
285 try:
286 prompt = element["metadata"]["dalle"]["prompt"]
287 file_id = element["asset_pointer"].split("file-service://", 1)[1]
288 except Exception as e:
289 raise RuntimeError(f"No Image: {e.__class__.__name__}: {e}")
287 290 try:
288 291 async with session.get(f"{cls.url}/backend-api/files/{file_id}/download", headers=headers) as response:
289 292 cls._update_request_args(session)
@@ -380,9 +383,8 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
380 383 image_request = await cls.upload_image(session, cls._headers, image, image_name) if image else None
381 384 except Exception as e:
382 385 image_request = None
383 if debug.logging:
384 print("OpenaiChat: Upload image failed")
385 print(f"{e.__class__.__name__}: {e}")
386 debug.log("OpenaiChat: Upload image failed")
387 debug.log(f"{e.__class__.__name__}: {e}")
386 388 model = cls.get_model(model)
387 389 if conversation is None:
388 390 conversation = Conversation(conversation_id, str(uuid.uuid4()) if parent_id is None else parent_id)
@@ -419,11 +421,10 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
419 421 user_agent=cls._headers["user-agent"],
420 422 proof_token=RequestConfig.proof_token
421 423 )
422 if debug.logging:
423 print(
424 'Arkose:', False if not need_arkose else RequestConfig.arkose_token[:12]+"...",
425 'Proofofwork:', False if proofofwork is None else proofofwork[:12]+"...",
426 )
424 [debug.log(text) for text in (
425 f"Arkose: {'False' if not need_arkose else RequestConfig.arkose_token[:12]+'...'}",
426 f"Proofofwork: {'False' if proofofwork is None else proofofwork[:12]+'...'}",
427 )]
427 428 ws = None
428 429 if need_arkose:
429 430 async with session.post(f"{cls.url}/backend-api/register-websocket", headers=cls._headers) as response:
@@ -444,6 +445,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
444 445 }
445 446 if conversation.conversation_id is not None:
446 447 data["conversation_id"] = conversation.conversation_id
448 debug.log(f"OpenaiChat: Use conversation: {conversation.conversation_id}")
447 449 if action != "continue":
448 450 messages = messages if conversation_id is None else [messages[-1]]
449 451 data["messages"] = cls.create_messages(messages, image_request)
@@ -468,8 +470,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
468 470 cls._update_request_args(session)
469 471 if response.status == 403 and max_retries > 0:
470 472 max_retries -= 1
471 if debug.logging:
472 print(f"Retry: Error {response.status}: {await response.text()}")
473 debug.log(f"Retry: Error {response.status}: {await response.text()}")
473 474 await asyncio.sleep(5)
474 475 continue
475 476 await raise_for_status(response)
@@ -553,20 +554,27 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
553 554 elif isinstance(v, dict):
554 555 if fields.conversation_id is None:
555 556 fields.conversation_id = v.get("conversation_id")
556 fields.message_id = v.get("message", {}).get("id")
557 c = v.get("message", {}).get("content", {})
558 if c.get("content_type") == "multimodal_text":
559 generated_images = []
560 for element in c.get("parts"):
561 if element.get("content_type") == "image_asset_pointer":
562 generated_images.append(
563 cls.get_generated_image(session, cls._headers, element)
564 )
565 elif element.get("content_type") == "text":
566 for part in element.get("parts", []):
567 yield part
568 for image_response in await asyncio.gather(*generated_images):
569 yield image_response
557 debug.log(f"OpenaiChat: New conversation: {fields.conversation_id}")
558 m = v.get("message", {})
559 if m.get("author", {}).get("role") == "assistant":
560 fields.message_id = v.get("message", {}).get("id")
561 c = m.get("content", {})
562 if c.get("content_type") == "multimodal_text":
563 generated_images = []
564 for element in c.get("parts"):
565 if isinstance(element, str):
566 debug.log(f"No image or text: {line}")
567 elif element.get("content_type") == "image_asset_pointer":
568 generated_images.append(
569 cls.get_generated_image(session, cls._headers, element)
570 )
571 elif element.get("content_type") == "text":
572 for part in element.get("parts", []):
573 yield part
574 for image_response in await asyncio.gather(*generated_images):
575 yield image_response
576 else:
577 debug.log(f"OpenaiChat: {line}")
570 578 return
571 579 if "error" in line and line.get("error"):
572 580 raise RuntimeError(line.get("error"))
@@ -579,8 +587,7 @@ class OpenaiChat(AsyncGeneratorProvider, ProviderModelMixin):
579 587 user_data_dir = user_config_dir("g4f-nodriver")
580 588 else:
581 589 user_data_dir = None
582 if debug.logging:
583 print(f"Open nodriver with user_dir: {user_data_dir}")
590 debug.log(f"Open nodriver with user_dir: {user_data_dir}")
584 591 browser = await nodriver.start(
585 592 user_data_dir=user_data_dir,
586 593 browser_args=None if proxy is None else [f"--proxy-server={proxy}"],
Modified g4f/Provider/openai/har_file.py +2 -3
@@ -71,8 +71,7 @@ def readHAR():
71 71 if "openai-sentinel-turnstile-token" in v_headers:
72 72 RequestConfig.turnstile_token = v_headers["openai-sentinel-turnstile-token"]
73 73 except Exception as e:
74 if debug.logging:
75 print(f"Read proof token: {e}")
74 debug.log(f"Read proof token: {e}")
76 75 if arkose_url == v['request']['url']:
77 76 RequestConfig.arkose_request = parseHAREntry(v)
78 77 elif v['request']['url'] == start_url or v['request']['url'].startswith(conversation_url):
@@ -150,7 +149,7 @@ def getN() -> str:
150 149 return base64.b64encode(timestamp.encode()).decode()
151 150
152 151 async def get_request_config(proxy: str) -> RequestConfig:
153 if RequestConfig.arkose_request is None or RequestConfig.access_token is None:
152 if RequestConfig.access_token is None:
154 153 readHAR()
155 154 if RequestConfig.arkose_request is not None:
156 155 RequestConfig.arkose_token = await sendRequest(genArkReq(RequestConfig.arkose_request), proxy)
Modified g4f/client/service.py +4 -5
@@ -83,11 +83,10 @@ def get_model_and_provider(model : Union[Model, str],
83 83 if not ignore_stream and not provider.supports_stream and stream:
84 84 raise StreamNotSupportedError(f'{provider.__name__} does not support "stream" argument')
85 85
86 if debug.logging:
87 if model:
88 print(f'Using {provider.__name__} provider and {model} model')
89 else:
90 print(f'Using {provider.__name__} provider')
86 if model:
87 debug.log(f'Using {provider.__name__} provider and {model} model')
88 else:
89 debug.log(f'Using {provider.__name__} provider')
91 90
92 91 debug.last_provider = provider
93 92 debug.last_model = model
Modified g4f/debug.py +6 -1
@@ -4,4 +4,9 @@ logging: bool = False
4 4 version_check: bool = True
5 5 last_provider: ProviderType = None
6 6 last_model: str = None
7 version: str = None
7 version: str = None
8 log_handler: callable = print
9
10 def log(text):
11 if logging:
12 log_handler(text)
Modified g4f/gui/client/index.html +5 -0
@@ -170,6 +170,10 @@
170 170 <i class="fa-solid fa-download"></i>
171 171 <a href="" onclick="return false;">Export Conversations</a>
172 172 </button>
173 <button id="showLog">
174 <i class="fa-solid fa-terminal"></i>
175 <a href="" onclick="return false;">Show log</a>
176 </button>
173 177 </div>
174 178 </div>
175 179 <div class="conversation">
@@ -257,6 +261,7 @@
257 261 </div>
258 262 </div>
259 263 </div>
264 <div class="log hidden"></div>
260 265 </div>
261 266 <div class="mobile-sidebar">
262 267 <i class="fa-solid fa-bars"></i>
Modified g4f/gui/client/static/css/style.css +10 -1
@@ -1051,13 +1051,22 @@ a:-webkit-any-link {
1051 1051 padding: var(--inner-gap) var(--inner-gap) var(--inner-gap) 0;
1052 1052 }
1053 1053
1054 .settings, .images {
1054 .settings, .log {
1055 1055 width: 100%;
1056 1056 display: flex;
1057 1057 flex-direction: column;
1058 1058 overflow: auto;
1059 1059 }
1060 1060
1061 .log {
1062 white-space: pre-wrap;
1063 font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace;
1064 }
1065
1066 .log.hidden {
1067 display: none;
1068 }
1069
1061 1070 .settings .paper {
1062 1071 flex-direction: column;
1063 1072 min-width: 400px;
Modified g4f/gui/client/static/js/chat.v1.js +18 -1
@@ -19,6 +19,7 @@ const systemPrompt = document.getElementById("systemPrompt");
19 19 const settings = document.querySelector(".settings");
20 20 const chat = document.querySelector(".conversation");
21 21 const album = document.querySelector(".images");
22 const log_storage = document.querySelector(".log");
22 23
23 24 const optionElements = document.querySelectorAll(".settings input, .settings textarea, #model, #model2, #provider")
24 25
@@ -400,6 +401,9 @@ async function add_message_chunk(message, message_index) {
400 401 error_storage[message_index] = message.error
401 402 console.error(message.error);
402 403 content_map.inner.innerHTML += `<p><strong>An error occured:</strong> ${message.error}</p>`;
404 let p = document.createElement("p");
405 p.innerText = message.error;
406 log_storage.appendChild(p);
403 407 } else if (message.type == "preview") {
404 408 content_map.inner.innerHTML = markdown_render(message.preview);
405 409 } else if (message.type == "content") {
@@ -419,6 +423,10 @@ async function add_message_chunk(message, message_index) {
419 423 content_map.inner.innerHTML = html;
420 424 content_map.count.innerText = count_words_and_tokens(message_storage[message_index], provider_storage[message_index]?.model);
421 425 highlight(content_map.inner);
426 } else if (message.type == "log") {
427 let p = document.createElement("p");
428 p.innerText = message.log;
429 log_storage.appendChild(p);
422 430 }
423 431 window.scrollTo(0, 0);
424 432 if (message_box.scrollTop >= message_box.scrollHeight - message_box.clientHeight - 100) {
@@ -517,7 +525,7 @@ const ask_gpt = async (message_index = -1, message_id) => {
517 525 }
518 526 }
519 527 delete controller_storage[message_index];
520 if (!error && message_storage[message_index]) {
528 if (!error_storage[message_index] && message_storage[message_index]) {
521 529 const message_provider = message_index in provider_storage ? provider_storage[message_index] : null;
522 530 await add_message(window.conversation_id, "assistant", message_storage[message_index], message_provider);
523 531 await safe_load_conversation(window.conversation_id);
@@ -635,6 +643,7 @@ const set_conversation = async (conversation_id) => {
635 643 await load_conversation(conversation_id);
636 644 load_conversations();
637 645 hide_sidebar();
646 log_storage.classList.add("hidden");
638 647 };
639 648
640 649 const new_conversation = async () => {
@@ -647,6 +656,7 @@ const new_conversation = async () => {
647 656 }
648 657 load_conversations();
649 658 hide_sidebar();
659 log_storage.classList.add("hidden");
650 660 say_hello();
651 661 };
652 662
@@ -945,6 +955,7 @@ function open_settings() {
945 955 settings.classList.add("hidden");
946 956 chat.classList.remove("hidden");
947 957 }
958 log_storage.classList.add("hidden");
948 959 }
949 960
950 961 function open_album() {
@@ -1476,3 +1487,9 @@ if (SpeechRecognition) {
1476 1487 }
1477 1488 });
1478 1489 }
1490
1491 document.getElementById("showLog").addEventListener("click", ()=> {
1492 log_storage.classList.remove("hidden");
1493 settings.classList.add("hidden");
1494 log_storage.scrollTop = log_storage.scrollHeight;
1495 });
Modified g4f/gui/server/api.py +12 -0
@@ -18,6 +18,7 @@ from g4f.requests.aiohttp import get_connector
18 18 from g4f.Provider import ProviderType, __providers__, __map__
19 19 from g4f.providers.base_provider import ProviderModelMixin, FinishReason
20 20 from g4f.providers.conversation import BaseConversation
21 from g4f import debug
21 22
22 23 logger = logging.getLogger(__name__)
23 24
@@ -140,6 +141,13 @@ class Api:
140 141 }
141 142
142 143 def _create_response_stream(self, kwargs: dict, conversation_id: str, provider: str) -> Iterator:
144 if debug.logging:
145 logs = []
146 print_callback = debug.log_handler
147 def log_handler(text: str):
148 logs.append(text)
149 print_callback(text)
150 debug.log_handler = log_handler
143 151 try:
144 152 result = ChatCompletion.create(**kwargs)
145 153 first = True
@@ -168,6 +176,10 @@ class Api:
168 176 yield self._format_json("content", str(ImageResponse(images, chunk.alt)))
169 177 elif not isinstance(chunk, FinishReason):
170 178 yield self._format_json("content", str(chunk))
179 if logs:
180 for log in logs:
181 yield self._format_json("log", str(log))
182 logs = []
171 183 except Exception as e:
172 184 logger.exception(e)
173 185 yield self._format_json('error', get_error_message(e))
Modified g4f/requests/raise_for_status.py +1 -1
@@ -11,7 +11,7 @@ class CloudflareError(ResponseStatusError):
11 11 ...
12 12
13 13 def is_cloudflare(text: str) -> bool:
14 if "<title>Attention Required! | Cloudflare</title>" in text:
14 if "<title>Attention Required! | Cloudflare</title>" in text or 'id="cf-cloudflare-status"' in text:
15 15 return True
16 16 return '<div id="cf-please-wait">' in text or "<title>Just a moment...</title>" in text
17 17