返回提交历史
Modified
g4f/Provider/Copilot.py
+3
-6
Modified
g4f/Provider/needs_auth/OpenaiChat.py
+35
-28
Modified
g4f/Provider/openai/har_file.py
+2
-3
Modified
g4f/client/service.py
+4
-5
Modified
g4f/debug.py
+6
-1
Modified
g4f/gui/client/index.html
+5
-0
Modified
g4f/gui/client/static/css/style.css
+10
-1
Modified
g4f/gui/client/static/js/chat.v1.js
+18
-1
Modified
g4f/gui/server/api.py
+12
-0
Modified
g4f/requests/raise_for_status.py
+1
-1
XFEstudio/gpt4free
Add show log option to gui
8f3fbee0
代码差异
10 个文件
+96
-46
@@ -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}"],
@@ -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}"],
@@ -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)
@@ -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
@@ -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)
@@ -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>
@@ -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;
@@ -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
});
@@ -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))
@@ -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