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

XFEstudio/gpt4free

Fix styling in GUI, improve mobile support

63b7e96c
hlohaus <983577+hlohaus@users.noreply.github.com>
提交于

代码差异

4 个文件 +55 -25
Modified g4f/api/__init__.py +4 -2
@@ -9,6 +9,7 @@ import shutil
9 9 from email.utils import formatdate
10 10 import os.path
11 11 import hashlib
12 import asyncio
12 13 from fastapi import FastAPI, Response, Request, UploadFile, Depends
13 14 from fastapi.middleware.wsgi import WSGIMiddleware
14 15 from fastapi.responses import StreamingResponse, RedirectResponse, HTMLResponse, JSONResponse
@@ -540,8 +541,9 @@ class Api:
540 541 content_type = getattr(provider_handler, "synthesize_content_type", "application/octet-stream")
541 542 return StreamingResponse(response_data, media_type=content_type)
542 543
543 @self.app.get("/json/{filename}")
544 @self.app.post("/json/{filename}")
544 545 async def get_json(filename, request: Request):
546 await asyncio.sleep(30)
545 547 return ""
546 548
547 549 @self.app.get("/images/{filename}", responses={
@@ -580,7 +582,7 @@ class Api:
580 582 if len(source_url) > 1:
581 583 source_url = source_url[1]
582 584 source_url = source_url.replace("%2F", "/").replace("%3A", ":").replace("%3F", "?")
583 if source_url.startswith("http"):
585 if source_url.startswith("https://"):
584 586 await copy_images(
585 587 [source_url],
586 588 target=target)
Modified g4f/gui/client/index.html +1 -1
@@ -248,7 +248,7 @@
248 248 </div>
249 249 </div>
250 250 <div class="user-input">
251 <div class="box input-box">
251 <div class="box input-area">
252 252 <textarea id="message-input" placeholder="Ask a question" cols="30" rows="10"
253 253 style="white-space: pre-wrap;resize: none;"></textarea>
254 254 <label class="file-label image-label" for="image" title="">
Modified g4f/gui/client/static/css/style.css +16 -8
@@ -971,10 +971,10 @@ select:hover,
971 971 }
972 972 }
973 973
974 .input-box {
974 .input-area {
975 975 display: flex;
976 976 align-items: center;
977 cursor: pointer;
977 padding: 10px;
978 978 }
979 979
980 980 .info {
@@ -1150,6 +1150,7 @@ ul {
1150 1150 align-items: flex-start;
1151 1151 flex-wrap: wrap;
1152 1152 gap: 8px;
1153 padding-left: 4px;
1153 1154 }
1154 1155
1155 1156 .mobile-sidebar {
@@ -1317,19 +1318,20 @@ ul {
1317 1318 border: 1px dashed #e4d4ffa6;
1318 1319 border-radius: 4px;
1319 1320 cursor: pointer;
1320 padding-left: 4px;
1321 padding-right: 5px;
1322 padding-top: 2px;
1323 padding-bottom: 2px;
1324 1321 position: absolute;
1325 1322 bottom: 8px;
1326 right: 8px;
1323 right: 4px;
1324 padding: 4px;
1327 1325 }
1328 1326
1329 1327 #send-button:hover {
1330 1328 border: 1px solid #e4d4ffc9;
1331 1329 }
1332 1330
1331 #send-button i {
1332 padding: 2px;
1333 }
1334
1333 1335 form textarea {
1334 1336 height: 20px;
1335 1337 min-height: 20px;
@@ -1434,7 +1436,13 @@ form .field.saved .fa-xmark {
1434 1436
1435 1437 #message-input {
1436 1438 height: 90px;
1437 margin-left: 20px;
1439 flex: 1;
1440 padding: 10px;
1441 padding-left: 20px;
1442 border-radius: 20px;
1443 font-size: 14px;
1444 margin-right: 10px;
1445 outline: none;
1438 1446 max-height: 200px;
1439 1447 }
1440 1448
Modified g4f/gui/client/static/js/chat.v1.js +34 -14
@@ -39,7 +39,7 @@ let reasoning_storage = {}
39 39 let is_demo = false;
40 40
41 41 messageInput.addEventListener("blur", () => {
42 window.scrollTo(0, 0);
42 document.documentElement.scrollTop = 0;
43 43 });
44 44
45 45 messageInput.addEventListener("focus", () => {
@@ -244,16 +244,23 @@ const register_message_buttons = async () => {
244 244 if (!("click" in el.dataset)) {
245 245 el.dataset.click = "true";
246 246 el.addEventListener("click", async () => {
247 let message_el = get_message_el(el);
248 247 const elem = window.document.createElement('a');
249 248 let filename = `chat ${new Date().toLocaleString()}.md`.replaceAll(":", "-");
250 elem.href = message_el.dataset.object_url;
249 const conversation = await get_conversation(window.conversation_id);
250 let buffer = "";
251 conversation.items.forEach(message => {
252 buffer += `${message.role == 'user' ? 'User' : 'Assistant'}: ${message.content.trim()}\n\n\n`;
253 });
254 const file = new File([buffer.trim()], 'message.md', {type: 'text/plain'});
255 const objectUrl = URL.createObjectURL(file);
256 elem.href = objectUrl;
251 257 elem.download = filename;
252 258 document.body.appendChild(elem);
253 259 elem.click();
254 260 document.body.removeChild(elem);
255 261 el.classList.add("clicked");
256 262 setTimeout(() => el.classList.remove("clicked"), 1000);
263 URL.revokeObjectURL(objectUrl);
257 264 })
258 265 }
259 266 });
@@ -1771,7 +1778,11 @@ function update_message(content_map, message_id, content = null, scroll = true)
1771 1778 let countFocus = messageInput;
1772 1779 const count_input = async () => {
1773 1780 if (countFocus.value) {
1774 inputCount.innerText = count_words_and_tokens(countFocus.value, get_selected_model()?.value);
1781 if (window.matchMedia("(pointer:coarse)")) {
1782 inputCount.innerText = `(${count_tokens(get_selected_model()?.value, countFocus.value)} tokens)`;
1783 } else {
1784 inputCount.innerText = count_words_and_tokens(countFocus.value, get_selected_model()?.value);
1785 }
1775 1786 } else {
1776 1787 inputCount.innerText = "";
1777 1788 }
@@ -1815,11 +1826,7 @@ async function on_load() {
1815 1826 let chat_url = new URL(window.location.href)
1816 1827 let chat_params = new URLSearchParams(chat_url.search);
1817 1828 if (chat_params.get("prompt")) {
1818 messageInput.value = chat_params.title
1819 + chat_params.title ? "\n\n\n" : ""
1820 + chat_params.prompt
1821 + chat_params.prompt && chat_params.url ? "\n\n\n" : ""
1822 + chat_params.url;
1829 messageInput.value = `${chat_params.title}\n${chat_params.prompt}\n${chat_params.url}`.trim();
1823 1830 messageInput.style.height = messageInput.scrollHeight + "px";
1824 1831 messageInput.focus();
1825 1832 //await handle_ask();
@@ -1870,7 +1877,8 @@ async function on_api() {
1870 1877 messageInput.addEventListener("keydown", async (evt) => {
1871 1878 if (prompt_lock) return;
1872 1879 // If not mobile and not shift enter
1873 if (!window.matchMedia("(pointer:coarse)").matches && evt.keyCode === 13 && !evt.shiftKey) {
1880 let do_enter = messageInput.value.endsWith("\n\n");
1881 if (do_enter || !window.matchMedia("(pointer:coarse)").matches && evt.keyCode === 13 && !evt.shiftKey) {
1874 1882 evt.preventDefault();
1875 1883 console.log("pressed enter");
1876 1884 prompt_lock = true;
@@ -1892,7 +1900,9 @@ async function on_api() {
1892 1900 stop_recognition();
1893 1901 await handle_ask(false);
1894 1902 });
1895 messageInput.focus();
1903 messageInput.addEventListener(`click`, async () => {
1904 stop_recognition();
1905 });
1896 1906
1897 1907 let provider_options = [];
1898 1908 models = await api("models");
@@ -2394,14 +2404,18 @@ async function load_provider_models(provider=null) {
2394 2404 if (models && models.length > 0) {
2395 2405 modelSelect.classList.add("hidden");
2396 2406 modelProvider.classList.remove("hidden");
2397 models.forEach((model) => {
2407 let defaultIndex = 0;
2408 models.forEach((model, i) => {
2398 2409 let option = document.createElement('option');
2399 2410 option.value = model.model;
2400 2411 option.dataset.label = model.model;
2401 2412 option.text = `${model.model}${model.image ? " (Image Generation)" : ""}${model.vision ? " (Image Upload)" : ""}`;
2402 option.selected = model.default;
2403 2413 modelProvider.appendChild(option);
2414 if (model.default) {
2415 defaultIndex = i;
2416 }
2404 2417 });
2418 modelProvider.selectedIndex = defaultIndex;
2405 2419 let value = appStorage.getItem(modelProvider.name);
2406 2420 if (value) {
2407 2421 modelProvider.value = value;
@@ -2411,7 +2425,12 @@ async function load_provider_models(provider=null) {
2411 2425 modelSelect.classList.remove("hidden");
2412 2426 }
2413 2427 };
2414 providerSelect.addEventListener("change", () => load_provider_models());
2428 providerSelect.addEventListener("change", () => {
2429 load_provider_models()
2430 messageInput.focus();
2431 });
2432 modelSelect.addEventListener("change", () => messageInput.focus());
2433 modelProvider.addEventListener("change", () => messageInput.focus());
2415 2434
2416 2435 document.getElementById("pin").addEventListener("click", async () => {
2417 2436 const pin_container = document.getElementById("pin_container");
@@ -2446,6 +2465,7 @@ switchInput.addEventListener("change", () => {
2446 2465 });
2447 2466 searchButton.addEventListener("click", async () => {
2448 2467 switchInput.click();
2468 messageInput.focus();
2449 2469 });
2450 2470
2451 2471 function save_storage() {