diff --git a/g4f/api/__init__.py b/g4f/api/__init__.py index cc0f0403..4539ed98 100644 --- a/g4f/api/__init__.py +++ b/g4f/api/__init__.py @@ -10,7 +10,6 @@ from email.utils import formatdate import os.path import hashlib import asyncio -from urllib.parse import quote_plus from fastapi import FastAPI, Response, Request, UploadFile, Depends from fastapi.middleware.wsgi import WSGIMiddleware from fastapi.responses import StreamingResponse, RedirectResponse, HTMLResponse, JSONResponse @@ -552,7 +551,7 @@ class Api: HTTP_404_NOT_FOUND: {} }) async def get_image(filename, request: Request): - target = os.path.join(images_dir, quote_plus(filename)) + target = os.path.join(images_dir, os.path.basename(filename)) ext = os.path.splitext(filename)[1][1:] stat_result = SimpleNamespace() stat_result.st_size = 0 diff --git a/g4f/gui/client/static/css/style.css b/g4f/gui/client/static/css/style.css index ba1acc42..2ba0862f 100644 --- a/g4f/gui/client/static/css/style.css +++ b/g4f/gui/client/static/css/style.css @@ -1122,6 +1122,7 @@ ul { justify-content: center; align-items: center; transition: all 0.3s ease; + padding: 10px 12px; } .mobile-sidebar i { @@ -1421,11 +1422,12 @@ form .field.saved .fa-xmark { line-height: 30px; } -.collapsible { +.field.collapsible { border: 1px solid var(--blur-border); border-radius: var(--border-radius-1); overflow: hidden; margin-bottom: 10px; + padding-right: 0; } .collapsible-header { @@ -1442,7 +1444,11 @@ form .field.saved .fa-xmark { } .collapsible-content { - padding: 10px; + padding: 0 10px; +} + +.collapsible-content.api-key { + width: 100%; } .collapsible-content.hidden { @@ -1539,6 +1545,7 @@ form .field.saved .fa-xmark { .conversations, .settings, .conversation { flex: 1 1 300px; min-width: 0; + height: 100%; } /* Media queries for mobile devices */ @@ -1557,92 +1564,9 @@ form .field.saved .fa-xmark { order: -1; min-height: 80vh; } - - .buttons .field { - flex: 1 1 auto; - } - - #model, #provider { - font-size: 14px; - padding: 6px; - } - - .user-input .input-area { - padding: 8px; - } - - textarea#message-input { - font-size: 14px; - } - - .mobile-sidebar { - display: block; - position: fixed; - top: 10px; - left: 10px; - z-index: 1000; - } - - .conversations { - position: fixed; - left: -100%; - top: 0; - bottom: 0; - transition: left 0.3s; - z-index: 999; - background: var(--bg-color); - } - - .conversations.active { - left: 0; - } -} - -/* Flexible form elements */ -.user-input .input-area { - display: flex; - flex-wrap: wrap; - gap: 8px; -} - -textarea { - max-width: 100%; - min-height: 50px; - resize: vertical; -} - -/* Adaptive buttons */ -button { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.file-label { - flex-shrink: 0; -} - -/* Adaptive model menu */ -#model, #provider { - max-width: 150px; - overflow: hidden; - text-overflow: ellipsis; } @media (max-width: 480px) { - .buttons .field { - flex: 1 1 100%; - } - - #model, #provider { - max-width: 100%; - } - - .toolbar { - flex-wrap: wrap; - gap: 5px; - } - .info .convo-title { font-size: 12px; } diff --git a/g4f/gui/client/static/js/chat.v1.js b/g4f/gui/client/static/js/chat.v1.js index 21f10d99..0c087084 100644 --- a/g4f/gui/client/static/js/chat.v1.js +++ b/g4f/gui/client/static/js/chat.v1.js @@ -1651,8 +1651,10 @@ window.addEventListener('popstate', hide_sidebar, false); sidebar_button.addEventListener("click", async () => { if (sidebar.classList.contains("shown")) { await hide_sidebar(); + chat.classList.remove("hidden"); } else { await show_menu(); + chat.classList.add("hidden"); } window.scrollTo(0, 0); }); @@ -2096,7 +2098,7 @@ async function on_api() { Providers API key - + `; settings.querySelector(".paper").appendChild(providersListContainer); @@ -2739,13 +2741,3 @@ document.getElementById("showLog").addEventListener("click", ()=> { settings.classList.add("hidden"); log_storage.scrollTop = log_storage.scrollHeight; }); - -document.querySelector('.mobile-sidebar').addEventListener('click', function() { - document.querySelector('.conversations').classList.toggle('active'); -}); - -document.addEventListener('click', function(e) { - if(!e.target.closest('.conversations') && !e.target.closest('.mobile-sidebar')) { - document.querySelector('.conversations').classList.remove('active'); - } -}); diff --git a/g4f/image/copy_images.py b/g4f/image/copy_images.py index b9a2c369..9cab4665 100644 --- a/g4f/image/copy_images.py +++ b/g4f/image/copy_images.py @@ -60,8 +60,8 @@ async def copy_images( ) as session: async def copy_image(image: str, target: str = None) -> str: """Process individual image and return its local URL""" - target_path = None - try: + target_path = target + if target_path is None: # Generate filename components file_hash = hashlib.sha256(image.encode()).hexdigest()[:16] timestamp = int(time.time()) @@ -88,7 +88,7 @@ async def copy_images( f"{extension}" ) target_path = os.path.join(images_dir, filename) - + try: # Handle different image types if image.startswith("data:"): with open(target_path, "wb") as f: diff --git a/g4f/tools/files.py b/g4f/tools/files.py index 20eb15c8..92ebb8dc 100644 --- a/g4f/tools/files.py +++ b/g4f/tools/files.py @@ -78,7 +78,7 @@ from ..providers.asyncio import to_sync_generator from ..errors import MissingRequirementsError from .. import debug -PLAIN_FILE_EXTENSIONS = ["txt", "xml", "json", "js", "har", "sh", "py", "php", "css", "yaml", "sql", "log", "csv", "twig", "md"] +PLAIN_FILE_EXTENSIONS = ["txt", "xml", "json", "js", "har", "sh", "py", "php", "css", "yaml", "sql", "log", "csv", "twig", "md", "arc"] PLAIN_CACHE = "plain.cache" DOWNLOADS_FILE = "downloads.json" FILE_LIST = "files.txt"