返回提交历史
Modified
.gitignore
+4
-1
Modified
g4f/Provider/You.py
+0
-2
Modified
g4f/gui/client/static/css/style.css
+20
-12
Modified
g4f/gui/client/static/js/chat.v1.js
+86
-57
Modified
g4f/providers/base_provider.py
+4
-1
Modified
g4f/requests/aiohttp.py
+6
-1
Modified
g4f/requests/curl_cffi.py
+14
-4
Modified
projects/text_to_speech/package.json
+1
-4
Modified
setup.py
+3
-0
XFEstudio/gpt4free
Some small fixes
65bcc8ae
代码差异
9 个文件
+138
-82
@@ -54,4 +54,7 @@ local.py
54
54
*.gguf
55
55
image.py
56
56
.buildozer
57
hardir
57
hardir
58
node_modules
59
models
60
projects/windows/g4f
@@ -10,8 +10,6 @@ from .base_provider import AsyncGeneratorProvider, ProviderModelMixin
10
10
from .helper import format_prompt
11
11
from ..image import ImageResponse, to_bytes, is_accepted_format
12
12
from ..requests import StreamSession, FormData, raise_for_status
13
from ..errors import MissingRequirementsError
14
15
13
from .you.har_file import get_dfp_telemetry_id
16
14
17
15
class You(AsyncGeneratorProvider, ProviderModelMixin):
@@ -646,6 +646,21 @@ select {
646
646
width: 160px;
647
647
}
648
648
649
#systemPrompt, .settings textarea {
650
font-size: 15px;
651
width: 100%;
652
color: var(--colour-3);
653
min-height: 50px;
654
height: 59px;
655
outline: none;
656
padding: var(--inner-gap) var(--section-gap);
657
resize: vertical;
658
}
659
660
#systemPrompt {
661
padding-left: 35px;
662
}
663
649
664
@media only screen and (min-width: 40em) {
650
665
select {
651
666
width: 200px;
@@ -836,6 +851,10 @@ ul {
836
851
.mobile-sidebar {
837
852
display: flex !important;
838
853
}
854
855
#systemPrompt {
856
padding-left: 48px;
857
}
839
858
}
840
859
841
860
.shown {
@@ -1064,22 +1083,11 @@ a:-webkit-any-link {
1064
1083
border: 1px solid #e4d4ffc9;
1065
1084
}
1066
1085
1067
#systemPrompt, .settings textarea {
1068
font-size: 15px;
1069
width: 100%;
1070
color: var(--colour-3);
1071
min-height: 50px;
1072
height: 59px;
1073
outline: none;
1074
padding: var(--inner-gap) var(--section-gap);
1075
resize: vertical;
1076
}
1077
1078
1086
.settings textarea {
1079
1087
height: 51px;
1080
1088
}
1081
1089
1082
.settings {
1090
.settings, .images {
1083
1091
width: 100%;
1084
1092
display: flex;
1085
1093
flex-direction: column;
@@ -10,13 +10,14 @@ const sendButton = document.getElementById("send-button");
10
10
const imageInput = document.getElementById("image");
11
11
const cameraInput = document.getElementById("camera");
12
12
const fileInput = document.getElementById("file");
13
const microLabel = document.querySelector(".micro-label")
14
const inputCount = document.getElementById("input-count")
13
const microLabel = document.querySelector(".micro-label");
14
const inputCount = document.getElementById("input-count");
15
15
const providerSelect = document.getElementById("provider");
16
16
const modelSelect = document.getElementById("model");
17
17
const modelProvider = document.getElementById("model2");
18
const systemPrompt = document.getElementById("systemPrompt")
19
const settings = document.querySelector(".settings")
18
const systemPrompt = document.getElementById("systemPrompt");
19
const settings = document.querySelector(".settings");
20
const album = document.querySelector(".images");
20
21
21
22
let prompt_lock = false;
22
23
@@ -49,6 +50,12 @@ const markdown_render = (content) => {
49
50
.replaceAll('<code>', '<code class="language-plaintext">')
50
51
}
51
52
53
function filter_message(text) {
54
return text.replaceAll(
55
/<!-- generated images start -->[\s\S]+<!-- generated images end -->/gm, ""
56
)
57
}
58
52
59
hljs.addPlugin(new CopyButtonPlugin());
53
60
let typesetPromise = Promise.resolve();
54
61
const highlight = (container) => {
@@ -64,7 +71,6 @@ const highlight = (container) => {
64
71
);
65
72
}
66
73
67
let stopped = false;
68
74
const register_message_buttons = async () => {
69
75
document.querySelectorAll(".message .fa-xmark").forEach(async (el) => {
70
76
if (!("click" in el.dataset)) {
@@ -95,69 +101,76 @@ const register_message_buttons = async () => {
95
101
if (!("click" in el.dataset)) {
96
102
el.dataset.click = "true";
97
103
el.addEventListener("click", async () => {
98
if ("active" in el.classList || window.doSpeech) {
99
el.classList.add("blink")
100
stopped = true;
101
return;
104
let playlist = [];
105
function play_next() {
106
const next = playlist.shift();
107
if (next)
108
next.play();
102
109
}
103
if (stopped) {
110
if (el.dataset.stopped) {
104
111
el.classList.remove("blink")
105
stopped = false;
112
delete el.dataset.stopped;
113
return;
114
}
115
if (el.dataset.running) {
116
el.dataset.stopped = true;
117
el.classList.add("blink")
118
playlist = [];
106
119
return;
107
120
}
121
el.dataset.running = true;
108
122
el.classList.add("blink")
109
123
el.classList.add("active")
110
const message_el = el.parentElement.parentElement.parentElement;
111
124
const content_el = el.parentElement.parentElement;
125
const message_el = content_el.parentElement;
112
126
let speechText = await get_message(window.conversation_id, message_el.dataset.index);
113
127
128
speechText = speechText.replaceAll(/([^0-9])\./gm, "$1.;");
129
speechText = speechText.replaceAll("?", "?;");
114
130
speechText = speechText.replaceAll(/\[(.+)\]\(.+\)/gm, "($1)");
115
speechText = speechText.replaceAll("`", "").replaceAll("#", "")
116
speechText = speechText.replaceAll(
117
/<!-- generated images start -->[\s\S]+<!-- generated images end -->/gm,
118
""
119
)
120
121
const lines = speechText.trim().split(/\n|\.|;/);
122
let ended = true;
131
speechText = speechText.replaceAll(/```[a-z]+/gm, "");
132
speechText = filter_message(speechText.replaceAll("`", "").replaceAll("#", ""))
133
const lines = speechText.trim().split(/\n|;/).filter(v => v.trim());
134
123
135
window.onSpeechResponse = (url) => {
124
el.classList.remove("blink")
136
if (!el.dataset.stopped) {
137
el.classList.remove("blink")
138
}
125
139
if (url) {
126
140
var sound = document.createElement('audio');
127
141
sound.controls = 'controls';
128
142
sound.src = url;
129
143
sound.type = 'audio/wav';
130
144
sound.onended = function() {
131
ended = true;
145
el.dataset.do_play = true;
146
setTimeout(play_next, 1000);
132
147
};
133
148
sound.onplay = function() {
134
ended = false;
149
delete el.dataset.do_play;
135
150
};
136
151
var container = document.createElement('div');
137
152
container.classList.add("audio");
138
153
container.appendChild(sound);
139
154
content_el.appendChild(container);
140
if (ended && !stopped) {
141
sound.play();
155
if (!el.dataset.stopped) {
156
playlist.push(sound);
157
if (el.dataset.do_play) {
158
play_next();
159
}
142
160
}
143
161
}
144
if (lines.length < 1 || stopped) {
162
let line = lines.length > 0 ? lines.shift() : null;
163
if (line && !el.dataset.stopped) {
164
handleGenerateSpeech(line);
165
} else {
145
166
el.classList.remove("active");
146
return;
147
}
148
while (lines.length > 0) {
149
let line = lines.shift();
150
var reg = new RegExp('^[0-9]$');
151
if (line && !reg.test(line)) {
152
return handleGenerateSpeech(line);
153
}
154
}
155
if (!line) {
156
el.classList.remove("active")
167
el.classList.remove("blink");
168
delete el.dataset.running;
157
169
}
158
170
}
171
el.dataset.do_play = true;
159
172
let line = lines.shift();
160
return handleGenerateSpeech(line);
173
handleGenerateSpeech(line);
161
174
});
162
175
}
163
176
});
@@ -399,7 +412,7 @@ const ask_gpt = async () => {
399
412
provider = "Bing";
400
413
let api_key = null;
401
414
if (provider)
402
api_key = document.getElementById(`${provider}-api_key`)?.value;
415
api_key = document.getElementById(`${provider}-api_key`)?.value || null;
403
416
await api("conversation", {
404
417
id: window.token,
405
418
conversation_id: window.conversation_id,
@@ -717,7 +730,7 @@ const load_conversations = async () => {
717
730
</div>
718
731
`;
719
732
});
720
box_conversations.innerHTML = html;
733
box_conversations.innerHTML += html;
721
734
};
722
735
723
736
document.getElementById("cancelButton").addEventListener("click", async () => {
@@ -790,6 +803,17 @@ function open_settings() {
790
803
}
791
804
}
792
805
806
function open_album() {
807
if (album.classList.contains("hidden")) {
808
sidebar.classList.remove("shown");
809
settings.classList.add("hidden");
810
album.classList.remove("hidden");
811
history.pushState({}, null, "/images/");
812
} else {
813
album.classList.add("hidden");
814
}
815
}
816
793
817
const register_settings_storage = async () => {
794
818
optionElements.forEach((element) => {
795
819
if (element.type == "textarea") {
@@ -1232,12 +1256,12 @@ if (SpeechRecognition) {
1232
1256
}
1233
1257
1234
1258
let startValue;
1235
let lastValue;
1236
1259
let timeoutHandle;
1260
let lastDebounceTranscript;
1237
1261
recognition.onstart = function() {
1238
1262
microLabel.classList.add("recognition");
1239
1263
startValue = messageInput.value;
1240
lastValue = "";
1264
lastDebounceTranscript = "";
1241
1265
timeoutHandle = window.setTimeout(may_stop, 8000);
1242
1266
};
1243
1267
recognition.onend = function() {
@@ -1248,22 +1272,27 @@ if (SpeechRecognition) {
1248
1272
return;
1249
1273
}
1250
1274
window.clearTimeout(timeoutHandle);
1251
let newText;
1252
Array.from(event.results).forEach((result) => {
1253
newText = result[0].transcript;
1254
if (newText && newText != lastValue) {
1255
messageInput.value = `${startValue ? startValue+"\n" : ""}${newText.trim()}`;
1256
if (result.isFinal) {
1257
lastValue = newText;
1258
startValue = messageInput.value;
1259
messageInput.focus();
1260
}
1261
messageInput.style.height = messageInput.scrollHeight + "px";
1262
messageInput.scrollTop = messageInput.scrollHeight;
1275
1276
let result = event.results[event.resultIndex];
1277
let isFinal = result.isFinal && (result[0].confidence > 0);
1278
let transcript = result[0].transcript;
1279
if (isFinal) {
1280
if(transcript == lastDebounceTranscript) {
1281
return;
1263
1282
}
1264
});
1265
window.clearTimeout(timeoutHandle);
1266
timeoutHandle = window.setTimeout(may_stop, newText ? 8000 : 5000);
1283
lastDebounceTranscript = transcript;
1284
}
1285
if (transcript) {
1286
messageInput.value = `${startValue ? startValue+"\n" : ""}${transcript.trim()}`;
1287
if (isFinal) {
1288
startValue = messageInput.value;
1289
messageInput.focus();
1290
}
1291
messageInput.style.height = messageInput.scrollHeight + "px";
1292
messageInput.scrollTop = messageInput.scrollHeight;
1293
}
1294
1295
timeoutHandle = window.setTimeout(may_stop, transcript ? 8000 : 5000);
1267
1296
};
1268
1297
1269
1298
microLabel.addEventListener("click", () => {
@@ -78,6 +78,7 @@ class AbstractProvider(BaseProvider):
78
78
timeout=kwargs.get("timeout")
79
79
)
80
80
81
@classmethod
81
82
def get_parameters(cls) -> dict:
82
83
return signature(
83
84
cls.create_async_generator if issubclass(cls, AsyncGeneratorProvider) else
@@ -107,7 +108,9 @@ class AbstractProvider(BaseProvider):
107
108
continue
108
109
args += f"\n {name}"
109
110
args += f": {get_type_name(param.annotation)}" if param.annotation is not Parameter.empty else ""
110
args += f' = "{param.default}"' if param.default == "" else f" = {param.default}" if param.default is not Parameter.empty else ""
111
default_value = f'"{param.default}"' if isinstance(param.default, str) else param.default
112
args += f" = {default_value}" if param.default is not Parameter.empty else ""
113
args += ","
111
114
112
115
return f"g4f.Provider.{cls.__name__} supports: ({args}\n)"
113
116
@@ -33,9 +33,14 @@ class StreamSession(ClientSession):
33
33
**DEFAULT_HEADERS,
34
34
**headers
35
35
}
36
connect = None
37
if isinstance(timeout, tuple):
38
connect, timeout = timeout;
39
if timeout is not None:
40
timeout = ClientTimeout(timeout, connect)
36
41
super().__init__(
37
42
**kwargs,
38
timeout=ClientTimeout(timeout) if timeout else None,
43
timeout=timeout,
39
44
response_class=StreamResponse,
40
45
connector=get_connector(connector, proxies.get("all", proxies.get("https"))),
41
46
headers=headers
@@ -1,6 +1,11 @@
1
1
from __future__ import annotations
2
2
3
from curl_cffi.requests import AsyncSession, Response, CurlMime
3
from curl_cffi.requests import AsyncSession, Response
4
try:
5
from curl_cffi.requests import CurlMime
6
has_curl_mime = True
7
except ImportError:
8
has_curl_mime = False
4
9
from typing import AsyncGenerator, Any
5
10
from functools import partialmethod
6
11
import json
@@ -78,6 +83,11 @@ class StreamSession(AsyncSession):
78
83
patch = partialmethod(request, "PATCH")
79
84
delete = partialmethod(request, "DELETE")
80
85
81
class FormData(CurlMime):
82
def add_field(self, name, data=None, content_type: str = None, filename: str = None) -> None:
83
self.addpart(name, content_type=content_type, filename=filename, data=data)
86
if has_curl_mime:
87
class FormData(CurlMime):
88
def add_field(self, name, data=None, content_type: str = None, filename: str = None) -> None:
89
self.addpart(name, content_type=content_type, filename=filename, data=data)
90
else:
91
class FormData():
92
def __init__(self) -> None:
93
raise RuntimeError("CurlMimi in curl_cffi is missing | pip install -U g4f[curl_cffi]")
@@ -12,8 +12,5 @@
12
12
"pack": "^2.2.0",
13
13
"web": "^0.0.2",
14
14
"webpack-cli": "^5.1.4"
15
},
16
"bundleDependencies": [
17
"@xenova/transformers"
18
]
15
}
19
16
}
@@ -74,6 +74,9 @@ EXTRA_REQUIRE = {
74
74
],
75
75
"local": [
76
76
"gpt4all"
77
],
78
"curl_cffi": [
79
"curl_cffi>=0.6.2",
77
80
]
78
81
}
79
82