返回提交历史
Modified
g4f/gui/client/static/js/chat.v1.js
+190
-100
Modified
g4f/gui/server/backend_api.py
+3
-1
XFEstudio/gpt4free
Handle demo modus in Web UI
5a0afdb1
代码差异
2 个文件
+193
-101
@@ -36,6 +36,7 @@ let parameters_storage = {};
36
36
let finish_storage = {};
37
37
let usage_storage = {};
38
38
let reasoning_storage = {}
39
let is_demo = false;
39
40
40
41
messageInput.addEventListener("blur", () => {
41
42
window.scrollTo(0, 0);
@@ -683,7 +684,7 @@ async function load_provider_parameters(provider) {
683
684
}
684
685
}
685
686
686
async function add_message_chunk(message, message_id, provider, scroll) {
687
async function add_message_chunk(message, message_id, provider, scroll, finish_message=null) {
687
688
content_map = content_storage[message_id];
688
689
if (message.type == "conversation") {
689
690
const conversation = await get_conversation(window.conversation_id);
@@ -737,6 +738,9 @@ async function add_message_chunk(message, message_id, provider, scroll) {
737
738
update_message(content_map, message_id, markdown_render(message.login), scroll);
738
739
} else if (message.type == "finish") {
739
740
finish_storage[message_id] = message.finish;
741
if (finish_message) {
742
await finish_message();
743
}
740
744
} else if (message.type == "usage") {
741
745
usage_storage[message_id] = message.usage;
742
746
} else if (message.type == "reasoning") {
@@ -829,11 +833,67 @@ const ask_gpt = async (message_id, message_index = -1, regenerate = false, provi
829
833
if (scroll) {
830
834
await lazy_scroll_to_bottom();
831
835
}
836
async function finish_message() {
837
content_map.update_timeouts.forEach((timeoutId)=>clearTimeout(timeoutId));
838
content_map.update_timeouts = [];
839
if (!error_storage[message_id] && message_storage[message_id]) {
840
html = markdown_render(message_storage[message_id]);
841
content_map.inner.innerHTML = html;
842
highlight(content_map.inner);
843
if (imageInput) imageInput.value = "";
844
if (cameraInput) cameraInput.value = "";
845
}
846
if (message_storage[message_id]) {
847
const message_provider = message_id in provider_storage ? provider_storage[message_id] : null;
848
await add_message(
849
window.conversation_id,
850
"assistant",
851
message_storage[message_id] + (error_storage[message_id] ? " [error]" : "") + (stop_generating.classList.contains('stop_generating-hidden') ? " [aborted]" : ""),
852
message_provider,
853
message_index,
854
synthesize_storage[message_id],
855
regenerate,
856
title_storage[message_id],
857
finish_storage[message_id],
858
usage_storage[message_id],
859
reasoning_storage[message_id],
860
action=="continue"
861
);
862
delete message_storage[message_id];
863
}
864
if (controller_storage[message_id]) {
865
if (!controller_storage[message_id].signal.aborted) {
866
controller_storage[message_id].abort();
867
}
868
delete controller_storage[message_id];
869
}
870
if (!error_storage[message_id]) {
871
await safe_load_conversation(window.conversation_id, scroll);
872
}
873
let cursorDiv = message_el.querySelector(".cursor");
874
if (cursorDiv) cursorDiv.parentNode.removeChild(cursorDiv);
875
if (scroll) {
876
await lazy_scroll_to_bottom();
877
}
878
await safe_remove_cancel_button();
879
await register_message_buttons();
880
await load_conversations();
881
regenerate_button.classList.remove("regenerate-hidden");
882
}
832
883
try {
884
let api_key;
885
if (is_demo && provider != "Custom") {
886
api_key = localStorage.getItem("HuggingFace-api_key");
887
if (!api_key) {
888
location.href = "/";
889
return;
890
}
891
} else {
892
api_key = get_api_key_by_provider(provider);
893
}
833
894
const input = imageInput && imageInput.files.length > 0 ? imageInput : cameraInput;
834
895
const files = input && input.files.length > 0 ? input.files : null;
835
896
const download_images = document.getElementById("download_images")?.checked;
836
const api_key = get_api_key_by_provider(provider);
837
897
const api_base = provider == "Custom" ? document.getElementById(`${provider}-api_base`).value : null;
838
898
const ignored = Array.from(settings.querySelectorAll("input.provider:not(:checked)")).map((el)=>el.value);
839
899
await api("conversation", {
@@ -849,54 +909,15 @@ const ask_gpt = async (message_id, message_index = -1, regenerate = false, provi
849
909
api_key: api_key,
850
910
api_base: api_base,
851
911
ignored: ignored,
852
}, files, message_id, scroll);
853
content_map.update_timeouts.forEach((timeoutId)=>clearTimeout(timeoutId));
854
content_map.update_timeouts = [];
855
if (!error_storage[message_id]) {
856
html = markdown_render(message_storage[message_id]);
857
content_map.inner.innerHTML = html;
858
highlight(content_map.inner);
859
if (imageInput) imageInput.value = "";
860
if (cameraInput) cameraInput.value = "";
861
}
912
}, files, message_id, scroll, finish_message);
862
913
} catch (e) {
863
914
console.error(e);
864
915
if (e.name != "AbortError") {
865
916
error_storage[message_id] = true;
866
917
content_map.inner.innerHTML += markdown_render(`**An error occured:** ${e}`);
867
918
}
919
await finish_message();
868
920
}
869
if (message_storage[message_id]) {
870
const message_provider = message_id in provider_storage ? provider_storage[message_id] : null;
871
await add_message(
872
window.conversation_id,
873
"assistant",
874
message_storage[message_id] + (error_storage[message_id] ? " [error]" : "") + (stop_generating.classList.contains('stop_generating-hidden') ? " [aborted]" : ""),
875
message_provider,
876
message_index,
877
synthesize_storage[message_id],
878
regenerate,
879
title_storage[message_id],
880
finish_storage[message_id],
881
usage_storage[message_id],
882
reasoning_storage[message_id],
883
action=="continue"
884
);
885
delete controller_storage[message_id];
886
delete message_storage[message_id];
887
if (!error_storage[message_id]) {
888
await safe_load_conversation(window.conversation_id, scroll);
889
}
890
}
891
let cursorDiv = message_el.querySelector(".cursor");
892
if (cursorDiv) cursorDiv.parentNode.removeChild(cursorDiv);
893
if (scroll) {
894
await lazy_scroll_to_bottom();
895
}
896
await safe_remove_cancel_button();
897
await register_message_buttons();
898
await load_conversations();
899
regenerate_button.classList.remove("regenerate-hidden");
900
921
};
901
922
902
923
async function scroll_to_bottom() {
@@ -1789,70 +1810,93 @@ async function on_api() {
1789
1810
models.forEach((model) => {
1790
1811
let option = document.createElement("option");
1791
1812
option.value = model.name;
1792
option.text = model.name + (model.image ? " (Image Generation)" : "");
1813
option.text = model.name + (model.image ? " (Image Generation)" : "") + (model.vision ? " (Image Upload)" : "");
1793
1814
option.dataset.providers = model.providers.join(" ");
1794
1815
modelSelect.appendChild(option);
1816
is_demo = model.demo;
1795
1817
});
1796
providers = await api("providers")
1797
providers.sort((a, b) => a.label.localeCompare(b.label));
1798
let login_urls = {};
1799
providers.forEach((provider) => {
1800
let option = document.createElement("option");
1801
option.value = provider.name;
1802
option.dataset.label = provider.label;
1803
option.text = provider.label
1804
+ (provider.vision ? " (Image Upload)" : "")
1805
+ (provider.image ? " (Image Generation)" : "")
1806
+ (provider.webdriver ? " (Webdriver)" : "")
1807
+ (provider.auth ? " (Auth)" : "");
1808
if (provider.parent)
1809
option.dataset.parent = provider.parent;
1810
providerSelect.appendChild(option);
1811
1812
if (provider.parent) {
1813
if (!login_urls[provider.parent]) {
1814
login_urls[provider.parent] = [provider.label, provider.login_url, [provider.name]];
1815
} else {
1816
login_urls[provider.parent][2].push(provider.name);
1818
let login_urls;
1819
if (is_demo) {
1820
if (!localStorage.getItem("HuggingFace-api_key")) {
1821
location.href = "/";
1822
return;
1823
}
1824
providerSelect.innerHTML = '<option value="" selected>Demo Modus</option>'
1825
document.getElementById("pin")?.remove();
1826
document.getElementById("refine")?.parentElement.remove();
1827
Array.from(modelSelect.querySelectorAll(':not([data-providers])')).forEach((option)=>{
1828
if (!option.disabled && option.value) {
1829
option.remove();
1817
1830
}
1818
} else if (provider.login_url) {
1819
if (!login_urls[provider.name]) {
1820
login_urls[provider.name] = [provider.label, provider.login_url, []];
1821
} else {
1822
login_urls[provider.name][0] = provider.label;
1823
login_urls[provider.name][1] = provider.login_url;
1831
});
1832
login_urls = {
1833
"Custom": ["Custom Provider", "", []],
1834
"HuggingFace": ["HuggingFace", "", []],
1835
};
1836
} else {
1837
providers = await api("providers")
1838
providers.sort((a, b) => a.label.localeCompare(b.label));
1839
login_urls = {};
1840
providers.forEach((provider) => {
1841
let option = document.createElement("option");
1842
option.value = provider.name;
1843
option.dataset.label = provider.label;
1844
option.text = provider.label
1845
+ (provider.vision ? " (Image Upload)" : "")
1846
+ (provider.image ? " (Image Generation)" : "")
1847
+ (provider.webdriver ? " (Webdriver)" : "")
1848
+ (provider.auth ? " (Auth)" : "");
1849
if (provider.parent)
1850
option.dataset.parent = provider.parent;
1851
providerSelect.appendChild(option);
1852
1853
if (provider.parent) {
1854
if (!login_urls[provider.parent]) {
1855
login_urls[provider.parent] = [provider.label, provider.login_url, [provider.name]];
1856
} else {
1857
login_urls[provider.parent][2].push(provider.name);
1858
}
1859
} else if (provider.login_url) {
1860
if (!login_urls[provider.name]) {
1861
login_urls[provider.name] = [provider.label, provider.login_url, []];
1862
} else {
1863
login_urls[provider.name][0] = provider.label;
1864
login_urls[provider.name][1] = provider.login_url;
1865
}
1824
1866
}
1825
}
1826
});
1867
});
1868
providers.forEach((provider) => {
1869
if (!provider.parent) {
1870
option = document.createElement("div");
1871
option.classList.add("field");
1872
option.innerHTML = `
1873
<span class="label">Enable ${provider.label}</span>
1874
<input id="Provider${provider.name}" type="checkbox" name="Provider${provider.name}" value="${provider.name}" class="provider" checked="">
1875
<label for="Provider${provider.name}" class="toogle" title="Remove provider from dropdown"></label>
1876
`;
1877
option.querySelector("input").addEventListener("change", (event) => load_provider_option(event.target, provider.name));
1878
settings.querySelector(".paper").appendChild(option);
1879
provider_options[provider.name] = option;
1880
}
1881
});
1882
await load_provider_models(appStorage.getItem("provider"))
1883
}
1827
1884
for (let [name, [label, login_url, childs]] of Object.entries(login_urls)) {
1828
if (!login_url) {
1885
if (!login_url && !is_demo) {
1829
1886
continue;
1830
1887
}
1831
1888
option = document.createElement("div");
1832
option.classList.add("field", "box", "hidden");
1889
option.classList.add("field", "box");
1890
if (!is_demo) {
1891
option.classList.add("hidden");
1892
}
1833
1893
childs = childs.map((child)=>`${child}-api_key`).join(" ");
1834
1894
option.innerHTML = `
1835
1895
<label for="${name}-api_key" class="label" title="">${label}:</label>
1836
<input type="text" id="${name}-api_key" name="${name}[api_key]" class="${childs}" placeholder="api_key"/>
1837
<a href="${login_url}" target="_blank" title="Login to ${label}">Get API key</a>
1838
`;
1896
<input type="text" id="${name}-api_key" name="${name}[api_key]" class="${childs}" placeholder="api_key" autocomplete="off"/>
1897
` + (login_url ? `<a href="${login_url}" target="_blank" title="Login to ${label}">Get API key</a>` : "");
1839
1898
settings.querySelector(".paper").appendChild(option);
1840
1899
}
1841
providers.forEach((provider) => {
1842
if (!provider.parent) {
1843
option = document.createElement("div");
1844
option.classList.add("field");
1845
option.innerHTML = `
1846
<span class="label">Enable ${provider.label}</span>
1847
<input id="Provider${provider.name}" type="checkbox" name="Provider${provider.name}" value="${provider.name}" class="provider" checked="">
1848
<label for="Provider${provider.name}" class="toogle" title="Remove provider from dropdown"></label>
1849
`;
1850
option.querySelector("input").addEventListener("change", (event) => load_provider_option(event.target, provider.name));
1851
settings.querySelector(".paper").appendChild(option);
1852
provider_options[provider.name] = option;
1853
}
1854
});
1855
await load_provider_models(appStorage.getItem("provider"))
1856
1900
1857
1901
register_settings_storage();
1858
1902
await load_settings_storage()
@@ -2093,7 +2137,7 @@ function get_selected_model() {
2093
2137
}
2094
2138
}
2095
2139
2096
async function api(ressource, args=null, files=null, message_id=null, scroll=true) {
2140
async function api(ressource, args=null, files=null, message_id=null, scroll=true, finish_message=null) {
2097
2141
if (window?.pywebview) {
2098
2142
if (args !== null) {
2099
2143
if (ressource == "conversation") {
@@ -2138,16 +2182,43 @@ async function api(ressource, args=null, files=null, message_id=null, scroll=tru
2138
2182
headers: headers,
2139
2183
body: body,
2140
2184
});
2141
return read_response(response, message_id, args.provider || null, scroll);
2185
// On Ratelimit
2186
if (response.status == 429) {
2187
// They are still pending requests?
2188
for (let key in controller_storage) {
2189
if (!controller_storage[key].signal.aborted) {
2190
console.error(response);
2191
await finish_message();
2192
return;
2193
}
2194
}
2195
setTimeout(async () => {
2196
response = await fetch(url, {
2197
method: 'POST',
2198
signal: controller_storage[message_id].signal,
2199
headers: headers,
2200
body: body,
2201
});
2202
if (response.status != 200) {
2203
console.error(response);
2204
}
2205
await read_response(response, message_id, args.provider || null, scroll, finish_message);
2206
await finish_message();
2207
}, 20000) // Wait 20 secounds on rate limit
2208
} else {
2209
await read_response(response, message_id, args.provider || null, scroll, finish_message);
2210
await finish_message();
2211
return;
2212
}
2142
2213
}
2143
2214
response = await fetch(url, {headers: headers});
2144
if (response.status == 200) {
2145
return await response.json();
2215
if (response.status != 200) {
2216
console.error(response);
2146
2217
}
2147
console.error(response);
2218
return await response.json();
2148
2219
}
2149
2220
2150
async function read_response(response, message_id, provider, scroll) {
2221
async function read_response(response, message_id, provider, scroll, finish_message) {
2151
2222
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
2152
2223
let buffer = ""
2153
2224
while (true) {
@@ -2160,7 +2231,7 @@ async function read_response(response, message_id, provider, scroll) {
2160
2231
continue;
2161
2232
}
2162
2233
try {
2163
add_message_chunk(JSON.parse(buffer + line), message_id, provider, scroll);
2234
add_message_chunk(JSON.parse(buffer + line), message_id, provider, scroll, finish_message);
2164
2235
buffer = "";
2165
2236
} catch {
2166
2237
buffer += line
@@ -2278,6 +2349,25 @@ function save_storage() {
2278
2349
}
2279
2350
}
2280
2351
2352
function add_memory() {
2353
let conversations = [];
2354
for (let i = 0; i < appStorage.length; i++) {
2355
if (appStorage.key(i).startsWith("conversation:")) {
2356
let conversation = appStorage.getItem(appStorage.key(i));
2357
conversations.push(JSON.parse(conversation));
2358
}
2359
}
2360
conversations.sort((a, b) => (b.updated||0)-(a.updated||0));
2361
conversations.forEach(async (conversation)=>{
2362
let body = JSON.stringify(conversation);
2363
response = await fetch("/backend-api/v2/memory", {
2364
method: 'POST',
2365
body: body,
2366
headers: {"content-type": "application/json"}
2367
});
2368
});
2369
}
2370
2281
2371
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
2282
2372
if (SpeechRecognition) {
2283
2373
const mircoIcon = microLabel.querySelector("i");
@@ -71,7 +71,9 @@ class Backend_Api(Api):
71
71
else:
72
72
class Dummy():
73
73
def limit(self, value):
74
pass
74
def callback(v):
75
return v
76
return callback
75
77
limiter = Dummy()
76
78
77
79
@app.route('/backend-api/v2/models', methods=['GET'])