From 1d9c745b35048ff0a04b08da42c2c9d0e1021dcb Mon Sep 17 00:00:00 2001 From: Tang Ziya Date: Thu, 9 May 2024 12:00:03 +0800 Subject: [PATCH 01/29] fix: replace deprecated on_event with lifespan --- backend/apps/litellm/main.py | 19 +++++++++++-------- backend/main.py | 27 ++++++++++++++------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/backend/apps/litellm/main.py b/backend/apps/litellm/main.py index 95f442067..6db426439 100644 --- a/backend/apps/litellm/main.py +++ b/backend/apps/litellm/main.py @@ -1,4 +1,5 @@ import sys +from contextlib import asynccontextmanager from fastapi import FastAPI, Depends, HTTPException from fastapi.routing import APIRoute @@ -46,7 +47,16 @@ import asyncio import subprocess import yaml -app = FastAPI() + +@asynccontextmanager +async def lifespan(app: FastAPI): + log.info("startup_event") + # TODO: Check config.yaml file and create one + asyncio.create_task(start_litellm_background()) + yield + + +app = FastAPI(lifespan=lifespan) origins = ["*"] @@ -141,13 +151,6 @@ async def shutdown_litellm_background(): background_process = None -@app.on_event("startup") -async def startup_event(): - log.info("startup_event") - # TODO: Check config.yaml file and create one - asyncio.create_task(start_litellm_background()) - - app.state.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER app.state.MODEL_FILTER_LIST = MODEL_FILTER_LIST diff --git a/backend/main.py b/backend/main.py index 139819f7c..2d8d9ed68 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,3 +1,4 @@ +from contextlib import asynccontextmanager from bs4 import BeautifulSoup import json import markdown @@ -92,7 +93,19 @@ https://github.com/open-webui/open-webui """ ) -app = FastAPI(docs_url="/docs" if ENV == "dev" else None, redoc_url=None) + +@asynccontextmanager +async def lifespan(app: FastAPI): + if ENABLE_LITELLM: + asyncio.create_task(start_litellm_background()) + yield + if ENABLE_LITELLM: + await shutdown_litellm_background() + + +app = FastAPI( + docs_url="/docs" if ENV == "dev" else None, redoc_url=None, lifespan=lifespan +) app.state.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER app.state.MODEL_FILTER_LIST = MODEL_FILTER_LIST @@ -211,12 +224,6 @@ async def check_url(request: Request, call_next): return response -@app.on_event("startup") -async def on_startup(): - if ENABLE_LITELLM: - asyncio.create_task(start_litellm_background()) - - app.mount("/api/v1", webui_app) app.mount("/litellm/api", litellm_app) @@ -381,9 +388,3 @@ else: log.warning( f"Frontend build directory not found at '{FRONTEND_BUILD_DIR}'. Serving API only." ) - - -@app.on_event("shutdown") -async def shutdown_event(): - if ENABLE_LITELLM: - await shutdown_litellm_background() From 93aea0a4d4d05ec841bacf446be971a397e66914 Mon Sep 17 00:00:00 2001 From: "Derek Palmer (Creative)" Date: Thu, 9 May 2024 14:54:26 -0400 Subject: [PATCH 02/29] Removed version synatax as its no longer needed per Docker Docs --- docker-compose.api.yaml | 2 -- docker-compose.data.yaml | 2 -- docker-compose.gpu.yaml | 2 -- docker-compose.yaml | 2 -- 4 files changed, 8 deletions(-) diff --git a/docker-compose.api.yaml b/docker-compose.api.yaml index f19974e7d..8f8fbe59a 100644 --- a/docker-compose.api.yaml +++ b/docker-compose.api.yaml @@ -1,5 +1,3 @@ -version: '3.8' - services: ollama: # Expose Ollama API outside the container stack diff --git a/docker-compose.data.yaml b/docker-compose.data.yaml index a8f9f77b0..4b70601f8 100644 --- a/docker-compose.data.yaml +++ b/docker-compose.data.yaml @@ -1,5 +1,3 @@ -version: '3.8' - services: ollama: volumes: diff --git a/docker-compose.gpu.yaml b/docker-compose.gpu.yaml index 424f485a1..de821235d 100644 --- a/docker-compose.gpu.yaml +++ b/docker-compose.gpu.yaml @@ -1,5 +1,3 @@ -version: '3.8' - services: ollama: # GPU support diff --git a/docker-compose.yaml b/docker-compose.yaml index 9daba312a..74249febd 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,3 @@ -version: '3.8' - services: ollama: volumes: From ef8070d35dd5980aa92e7d6d4a9d66b0b16f7cf5 Mon Sep 17 00:00:00 2001 From: joecryptotoo <80373433+joecryptotoo@users.noreply.github.com> Date: Thu, 9 May 2024 12:25:26 -0700 Subject: [PATCH 03/29] added healthcheck --- Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index faee1ac32..e8ac47c8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -82,7 +82,7 @@ RUN echo -n 00000000-0000-0000-0000-000000000000 > $HOME/.cache/chroma/telemetry RUN if [ "$USE_OLLAMA" = "true" ]; then \ apt-get update && \ # Install pandoc and netcat - apt-get install -y --no-install-recommends pandoc netcat-openbsd && \ + apt-get install -y --no-install-recommends pandoc netcat-openbsd curl && \ # for RAG OCR apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \ # install helper tools @@ -94,7 +94,7 @@ RUN if [ "$USE_OLLAMA" = "true" ]; then \ else \ apt-get update && \ # Install pandoc and netcat - apt-get install -y --no-install-recommends pandoc netcat-openbsd && \ + apt-get install -y --no-install-recommends pandoc netcat-openbsd curl && \ # for RAG OCR apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \ # cleanup @@ -134,4 +134,6 @@ COPY ./backend . EXPOSE 8080 +HEALTHCHECK CMD curl --fail http://localhost:8080 || exit 1 + CMD [ "bash", "start.sh"] From a37440591147a4b1e2e122fb339bc47cbd9ac94f Mon Sep 17 00:00:00 2001 From: Yanyutin753 <132346501+Yanyutin753@users.noreply.github.com> Date: Fri, 10 May 2024 12:23:12 +0800 Subject: [PATCH 04/29] =?UTF-8?q?=F0=9F=8E=96=EF=B8=8FAdded=20translations?= =?UTF-8?q?=20for=20Citation=20and=20No=20source=20available?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/i18n/locales/ar-BH/translation.json | 8 +-- src/lib/i18n/locales/bg-BG/translation.json | 8 +-- src/lib/i18n/locales/bn-BD/translation.json | 8 +-- src/lib/i18n/locales/ca-ES/translation.json | 8 +-- src/lib/i18n/locales/dg-DG/translation.json | 4 +- src/lib/i18n/locales/es-ES/translation.json | 6 +- src/lib/i18n/locales/fa-IR/translation.json | 6 +- src/lib/i18n/locales/fr-CA/translation.json | 6 +- src/lib/i18n/locales/fr-FR/translation.json | 6 +- src/lib/i18n/locales/hi-IN/translation.json | 6 +- src/lib/i18n/locales/it-IT/translation.json | 6 +- src/lib/i18n/locales/ja-JP/translation.json | 6 +- src/lib/i18n/locales/ka-GE/translation.json | 6 +- src/lib/i18n/locales/ko-KR/translation.json | 6 +- src/lib/i18n/locales/nl-NL/translation.json | 8 +-- src/lib/i18n/locales/pl-PL/translation.json | 6 +- src/lib/i18n/locales/pt-BR/translation.json | 6 +- src/lib/i18n/locales/pt-PT/translation.json | 6 +- src/lib/i18n/locales/ru-RU/translation.json | 8 +-- src/lib/i18n/locales/sv-SE/translation.json | 6 +- src/lib/i18n/locales/tr-TR/translation.json | 6 +- src/lib/i18n/locales/vi-VN/translation.json | 6 +- src/lib/i18n/locales/zh-CN/translation.json | 72 ++++++++++----------- src/lib/i18n/locales/zh-TW/translation.json | 16 ++--- 24 files changed, 115 insertions(+), 115 deletions(-) diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index d57282afe..bc8a5e358 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Chunk تداخل", "Chunk Params": "Chunk المتغيرات", "Chunk Size": "Chunk حجم", - "Citation": "", + "Citation": "اقتباس", "Click here for help.": "أضغط هنا للمساعدة", "Click here to": "", "Click here to check other modelfiles.": "انقر هنا للتحقق من ملفات الموديلات الأخرى.", @@ -285,7 +285,7 @@ "New Chat": "دردشة جديدة", "New Password": "كلمة المرور الجديدة", "No results found": "", - "No source available": "", + "No source available": "لا يوجد مصدر متاح", "Not factually correct": "ليس صحيحا من حيث الواقع", "Not sure what to add?": "لست متأكدا ما يجب إضافته؟", "Not sure what to write? Switch to": "لست متأكدا ماذا أكتب؟ التبديل إلى", @@ -407,7 +407,7 @@ "Sign Out": "تسجيل الخروج", "Sign up": "تسجيل", "Signing in": "جاري الدخول", - "Source": "", + "Source": "المصدر", "Speech recognition error: {{error}}": "خطأ في التعرف على الكلام: {{error}}", "Speech-to-Text Engine": "محرك تحويل الكلام إلى نص", "SpeechRecognition API is not supported in this browser.": "API SpeechRecognition غير مدعومة في هذا المتصفح.", @@ -492,4 +492,4 @@ "You're now logged in.": "لقد قمت الآن بتسجيل الدخول.", "Youtube": "Youtube", "Youtube Loader Settings": "" -} +} \ No newline at end of file diff --git a/src/lib/i18n/locales/bg-BG/translation.json b/src/lib/i18n/locales/bg-BG/translation.json index 774aa8dd2..73fbb40d6 100644 --- a/src/lib/i18n/locales/bg-BG/translation.json +++ b/src/lib/i18n/locales/bg-BG/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Chunk Overlap", "Chunk Params": "Chunk Params", "Chunk Size": "Chunk Size", - "Citation": "", + "Citation": "Цитат", "Click here for help.": "Натиснете тук за помощ.", "Click here to": "", "Click here to check other modelfiles.": "Натиснете тук за проверка на други моделфайлове.", @@ -285,7 +285,7 @@ "New Chat": "Нов чат", "New Password": "Нова парола", "No results found": "", - "No source available": "", + "No source available": "Няма наличен източник", "Not factually correct": "", "Not sure what to add?": "Не сте сигурни, какво да добавите?", "Not sure what to write? Switch to": "Не сте сигурни, какво да напишете? Превключете към", @@ -407,7 +407,7 @@ "Sign Out": "Изход", "Sign up": "Регистрация", "Signing in": "", - "Source": "", + "Source": "Източник", "Speech recognition error: {{error}}": "Speech recognition error: {{error}}", "Speech-to-Text Engine": "Speech-to-Text Engine", "SpeechRecognition API is not supported in this browser.": "SpeechRecognition API is not supported in this browser.", @@ -492,4 +492,4 @@ "You're now logged in.": "Сега, вие влязохте в системата.", "Youtube": "", "Youtube Loader Settings": "" -} +} \ No newline at end of file diff --git a/src/lib/i18n/locales/bn-BD/translation.json b/src/lib/i18n/locales/bn-BD/translation.json index e41559393..4a34a66d2 100644 --- a/src/lib/i18n/locales/bn-BD/translation.json +++ b/src/lib/i18n/locales/bn-BD/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "চাঙ্ক ওভারল্যাপ", "Chunk Params": "চাঙ্ক প্যারামিটার্স", "Chunk Size": "চাঙ্ক সাইজ", - "Citation": "", + "Citation": "উদ্ধৃতি", "Click here for help.": "সাহায্যের জন্য এখানে ক্লিক করুন", "Click here to": "", "Click here to check other modelfiles.": "অন্যান্য মডেলফাইল চেক করার জন্য এখানে ক্লিক করুন", @@ -285,7 +285,7 @@ "New Chat": "নতুন চ্যাট", "New Password": "নতুন পাসওয়ার্ড", "No results found": "", - "No source available": "", + "No source available": "কোন উৎস পাওয়া যায়নি", "Not factually correct": "", "Not sure what to add?": "কী যুক্ত করতে হবে নিশ্চিত না?", "Not sure what to write? Switch to": "কী লিখতে হবে নিশ্চিত না? পরিবর্তন করুন:", @@ -407,7 +407,7 @@ "Sign Out": "সাইন আউট", "Sign up": "সাইন আপ", "Signing in": "", - "Source": "", + "Source": "উৎস", "Speech recognition error: {{error}}": "স্পিচ রিকগনিশনে সমস্যা: {{error}}", "Speech-to-Text Engine": "স্পিচ-টু-টেক্সট ইঞ্জিন", "SpeechRecognition API is not supported in this browser.": "এই ব্রাউজার স্পিচরিকগনিশন এপিআই সাপোর্ট করে না।", @@ -492,4 +492,4 @@ "You're now logged in.": "আপনি এখন লগইন করা অবস্থায় আছেন", "Youtube": "", "Youtube Loader Settings": "" -} +} \ No newline at end of file diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index faf96cb5a..bd8201a45 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Solapament de Blocs", "Chunk Params": "Paràmetres de Blocs", "Chunk Size": "Mida del Bloc", - "Citation": "", + "Citation": "Citació", "Click here for help.": "Fes clic aquí per ajuda.", "Click here to": "", "Click here to check other modelfiles.": "Fes clic aquí per comprovar altres fitxers de model.", @@ -285,7 +285,7 @@ "New Chat": "Xat Nou", "New Password": "Nova Contrasenya", "No results found": "", - "No source available": "", + "No source available": "Sense font disponible", "Not factually correct": "", "Not sure what to add?": "No estàs segur del que afegir?", "Not sure what to write? Switch to": "No estàs segur del que escriure? Canvia a", @@ -407,7 +407,7 @@ "Sign Out": "Tanca sessió", "Sign up": "Registra't", "Signing in": "", - "Source": "", + "Source": "Font", "Speech recognition error: {{error}}": "Error de reconeixement de veu: {{error}}", "Speech-to-Text Engine": "Motor de Veu a Text", "SpeechRecognition API is not supported in this browser.": "L'API de Reconèixer Veu no és compatible amb aquest navegador.", @@ -492,4 +492,4 @@ "You're now logged in.": "Ara estàs connectat.", "Youtube": "", "Youtube Loader Settings": "" -} +} \ No newline at end of file diff --git a/src/lib/i18n/locales/dg-DG/translation.json b/src/lib/i18n/locales/dg-DG/translation.json index d5565957b..0941ce2a4 100644 --- a/src/lib/i18n/locales/dg-DG/translation.json +++ b/src/lib/i18n/locales/dg-DG/translation.json @@ -285,7 +285,7 @@ "New Chat": "New Bark", "New Password": "New Barkword", "No results found": "", - "No source available": "", + "No source available": "No source available", "Not factually correct": "", "Not sure what to add?": "Not sure what to add?", "Not sure what to write? Switch to": "Not sure what to write? Switch to", @@ -407,7 +407,7 @@ "Sign Out": "Sign Out much logout", "Sign up": "Sign up much join", "Signing in": "", - "Source": "", + "Source": "Source", "Speech recognition error: {{error}}": "Speech recognition error: {{error}} so error", "Speech-to-Text Engine": "Speech-to-Text Engine much speak", "SpeechRecognition API is not supported in this browser.": "SpeechRecognition API is not supported in this browser. Much sad.", diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index 381e6ba30..024fc6fb8 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Superposición de fragmentos", "Chunk Params": "Parámetros de fragmentos", "Chunk Size": "Tamaño de fragmentos", - "Citation": "", + "Citation": "Cita", "Click here for help.": "Presiona aquí para obtener ayuda.", "Click here to": "", "Click here to check other modelfiles.": "Presiona aquí para consultar otros modelfiles.", @@ -285,7 +285,7 @@ "New Chat": "Nuevo Chat", "New Password": "Nueva Contraseña", "No results found": "", - "No source available": "", + "No source available": "No hay fuente disponible", "Not factually correct": "", "Not sure what to add?": "¿No sabes qué añadir?", "Not sure what to write? Switch to": "¿No sabes qué escribir? Cambia a", @@ -407,7 +407,7 @@ "Sign Out": "Cerrar sesión", "Sign up": "Crear una cuenta", "Signing in": "", - "Source": "", + "Source": "Fuente", "Speech recognition error: {{error}}": "Error de reconocimiento de voz: {{error}}", "Speech-to-Text Engine": "Motor de voz a texto", "SpeechRecognition API is not supported in this browser.": "La API SpeechRecognition no es compatible con este navegador.", diff --git a/src/lib/i18n/locales/fa-IR/translation.json b/src/lib/i18n/locales/fa-IR/translation.json index b346e31ef..3ae2a0866 100644 --- a/src/lib/i18n/locales/fa-IR/translation.json +++ b/src/lib/i18n/locales/fa-IR/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "همپوشانی تکه", "Chunk Params": "پارامترهای تکه", "Chunk Size": "اندازه تکه", - "Citation": "", + "Citation": "استناد", "Click here for help.": "برای کمک اینجا را کلیک کنید.", "Click here to": "", "Click here to check other modelfiles.": "برای بررسی سایر فایل\u200cهای مدل اینجا را کلیک کنید.", @@ -285,7 +285,7 @@ "New Chat": "گپ جدید", "New Password": "رمز عبور جدید", "No results found": "", - "No source available": "", + "No source available": "منبعی در دسترس نیست", "Not factually correct": "", "Not sure what to add?": "مطمئن نیستید چه چیزی را اضافه کنید؟", "Not sure what to write? Switch to": "مطمئن نیستید چه بنویسید؟ تغییر به", @@ -407,7 +407,7 @@ "Sign Out": "خروج", "Sign up": "ثبت نام", "Signing in": "", - "Source": "", + "Source": "منبع", "Speech recognition error: {{error}}": "خطای تشخیص گفتار: {{error}}", "Speech-to-Text Engine": "موتور گفتار به متن", "SpeechRecognition API is not supported in this browser.": "API تشخیص گفتار در این مرورگر پشتیبانی نمی شود.", diff --git a/src/lib/i18n/locales/fr-CA/translation.json b/src/lib/i18n/locales/fr-CA/translation.json index ba2034581..c15f1811c 100644 --- a/src/lib/i18n/locales/fr-CA/translation.json +++ b/src/lib/i18n/locales/fr-CA/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Chevauchement de bloc", "Chunk Params": "Paramètres de bloc", "Chunk Size": "Taille de bloc", - "Citation": "", + "Citation": "Citations", "Click here for help.": "Cliquez ici pour de l'aide.", "Click here to": "", "Click here to check other modelfiles.": "Cliquez ici pour vérifier d'autres fichiers de modèle.", @@ -285,7 +285,7 @@ "New Chat": "Nouvelle discussion", "New Password": "Nouveau mot de passe", "No results found": "", - "No source available": "", + "No source available": "Aucune source disponible", "Not factually correct": "", "Not sure what to add?": "Pas sûr de quoi ajouter ?", "Not sure what to write? Switch to": "Pas sûr de quoi écrire ? Changez pour", @@ -407,7 +407,7 @@ "Sign Out": "Se déconnecter", "Sign up": "S'inscrire", "Signing in": "", - "Source": "", + "Source": "Source", "Speech recognition error: {{error}}": "Erreur de reconnaissance vocale : {{error}}", "Speech-to-Text Engine": "Moteur reconnaissance vocale", "SpeechRecognition API is not supported in this browser.": "L'API SpeechRecognition n'est pas prise en charge dans ce navigateur.", diff --git a/src/lib/i18n/locales/fr-FR/translation.json b/src/lib/i18n/locales/fr-FR/translation.json index 22ce18089..91e9af25e 100644 --- a/src/lib/i18n/locales/fr-FR/translation.json +++ b/src/lib/i18n/locales/fr-FR/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Chevauchement de bloc", "Chunk Params": "Paramètres de bloc", "Chunk Size": "Taille de bloc", - "Citation": "", + "Citation": "Citations", "Click here for help.": "Cliquez ici pour de l'aide.", "Click here to": "", "Click here to check other modelfiles.": "Cliquez ici pour vérifier d'autres fichiers de modèle.", @@ -285,7 +285,7 @@ "New Chat": "Nouveau chat", "New Password": "Nouveau mot de passe", "No results found": "", - "No source available": "", + "No source available": "Aucune source disponible", "Not factually correct": "", "Not sure what to add?": "Vous ne savez pas quoi ajouter ?", "Not sure what to write? Switch to": "Vous ne savez pas quoi écrire ? Basculer vers", @@ -407,7 +407,7 @@ "Sign Out": "Se déconnecter", "Sign up": "S'inscrire", "Signing in": "", - "Source": "", + "Source": "Source", "Speech recognition error: {{error}}": "Erreur de reconnaissance vocale : {{error}}", "Speech-to-Text Engine": "Moteur de reconnaissance vocale", "SpeechRecognition API is not supported in this browser.": "L'API SpeechRecognition n'est pas prise en charge dans ce navigateur.", diff --git a/src/lib/i18n/locales/hi-IN/translation.json b/src/lib/i18n/locales/hi-IN/translation.json index 6e4fa9eaf..25930c461 100644 --- a/src/lib/i18n/locales/hi-IN/translation.json +++ b/src/lib/i18n/locales/hi-IN/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "चंक ओवरलैप", "Chunk Params": "चंक पैरामीटर्स", "Chunk Size": "चंक आकार", - "Citation": "", + "Citation": "उद्धरण", "Click here for help.": "सहायता के लिए यहां क्लिक करें।", "Click here to": "", "Click here to check other modelfiles.": "अन्य मॉडल फ़ाइलों की जांच के लिए यहां क्लिक करें।", @@ -285,7 +285,7 @@ "New Chat": "नई चैट", "New Password": "नया पासवर्ड", "No results found": "", - "No source available": "", + "No source available": "कोई स्रोत उपलब्ध नहीं है", "Not factually correct": "तथ्यात्मक रूप से सही नहीं है", "Not sure what to add?": "निश्चित नहीं कि क्या जोड़ें?", "Not sure what to write? Switch to": "मैं आश्वस्त नहीं हूं कि क्या लिखना है? स्विच करें", @@ -407,7 +407,7 @@ "Sign Out": "साइन आउट", "Sign up": "साइन अप", "Signing in": "साइन इन हो रहा है", - "Source": "", + "Source": "स्रोत", "Speech recognition error: {{error}}": "वाक् पहचान त्रुटि: {{error}}", "Speech-to-Text Engine": "वाक्-से-पाठ इंजन", "SpeechRecognition API is not supported in this browser.": "इस ब्राउज़र में SpeechRecognition API समर्थित नहीं है", diff --git a/src/lib/i18n/locales/it-IT/translation.json b/src/lib/i18n/locales/it-IT/translation.json index bb0949a64..f66ca586a 100644 --- a/src/lib/i18n/locales/it-IT/translation.json +++ b/src/lib/i18n/locales/it-IT/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Sovrapposizione chunk", "Chunk Params": "Parametri chunk", "Chunk Size": "Dimensione chunk", - "Citation": "", + "Citation": "Citazione", "Click here for help.": "Clicca qui per aiuto.", "Click here to": "", "Click here to check other modelfiles.": "Clicca qui per controllare altri file modello.", @@ -285,7 +285,7 @@ "New Chat": "Nuova chat", "New Password": "Nuova password", "No results found": "", - "No source available": "", + "No source available": "Nessuna fonte disponibile", "Not factually correct": "", "Not sure what to add?": "Non sei sicuro di cosa aggiungere?", "Not sure what to write? Switch to": "Non sei sicuro di cosa scrivere? Passa a", @@ -407,7 +407,7 @@ "Sign Out": "Esci", "Sign up": "Registrati", "Signing in": "", - "Source": "", + "Source": "Fonte", "Speech recognition error: {{error}}": "Errore di riconoscimento vocale: {{error}}", "Speech-to-Text Engine": "Motore da voce a testo", "SpeechRecognition API is not supported in this browser.": "L'API SpeechRecognition non è supportata in questo browser.", diff --git a/src/lib/i18n/locales/ja-JP/translation.json b/src/lib/i18n/locales/ja-JP/translation.json index 023befa71..7ce750a7d 100644 --- a/src/lib/i18n/locales/ja-JP/translation.json +++ b/src/lib/i18n/locales/ja-JP/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "チャンクオーバーラップ", "Chunk Params": "チャンクパラメーター", "Chunk Size": "チャンクサイズ", - "Citation": "", + "Citation": "引用文", "Click here for help.": "ヘルプについてはここをクリックしてください。", "Click here to": "", "Click here to check other modelfiles.": "他のモデルファイルを確認するにはここをクリックしてください。", @@ -285,7 +285,7 @@ "New Chat": "新しいチャット", "New Password": "新しいパスワード", "No results found": "", - "No source available": "", + "No source available": "使用可能なソースがありません", "Not factually correct": "", "Not sure what to add?": "何を追加すればよいかわからない?", "Not sure what to write? Switch to": "何を書けばよいかわからない? 次に切り替える", @@ -407,7 +407,7 @@ "Sign Out": "サインアウト", "Sign up": "サインアップ", "Signing in": "", - "Source": "", + "Source": "ソース", "Speech recognition error: {{error}}": "音声認識エラー: {{error}}", "Speech-to-Text Engine": "音声テキスト変換エンジン", "SpeechRecognition API is not supported in this browser.": "このブラウザでは SpeechRecognition API がサポートされていません。", diff --git a/src/lib/i18n/locales/ka-GE/translation.json b/src/lib/i18n/locales/ka-GE/translation.json index 609505b49..fb7eaf198 100644 --- a/src/lib/i18n/locales/ka-GE/translation.json +++ b/src/lib/i18n/locales/ka-GE/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "გადახურვა ფრაგმენტულია", "Chunk Params": "გადახურვის პარამეტრები", "Chunk Size": "გადახურვის ზომა", - "Citation": "", + "Citation": "ციტატა", "Click here for help.": "დახმარებისთვის, დააკლიკე აქ", "Click here to": "", "Click here to check other modelfiles.": "სხვა მოდელური ფაილების სანახავად, დააკლიკე აქ", @@ -285,7 +285,7 @@ "New Chat": "ახალი მიმოწერა", "New Password": "ახალი პაროლი", "No results found": "", - "No source available": "", + "No source available": "წყარო არ არის ხელმისაწვდომი", "Not factually correct": "", "Not sure what to add?": "არ იცი რა დაამატო?", "Not sure what to write? Switch to": "არ იცი რა დაწერო? გადართვა:", @@ -407,7 +407,7 @@ "Sign Out": "გასვლა", "Sign up": "რეგისტრაცია", "Signing in": "", - "Source": "", + "Source": "წყარო", "Speech recognition error: {{error}}": "მეტყველების ამოცნობის შეცდომა: {{error}}", "Speech-to-Text Engine": "ხმოვან-ტექსტური ძრავი", "SpeechRecognition API is not supported in this browser.": "მეტყველების ამოცნობის API არ არის მხარდაჭერილი ამ ბრაუზერში.", diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index dddc345e0..bcc625104 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Chunk Overlap", "Chunk Params": "Chunk Params", "Chunk Size": "Chunk Size", - "Citation": "", + "Citation": "인용", "Click here for help.": "도움말을 보려면 여기를 클릭하세요.", "Click here to": "", "Click here to check other modelfiles.": "다른 모델파일을 확인하려면 여기를 클릭하세요.", @@ -285,7 +285,7 @@ "New Chat": "새 채팅", "New Password": "새 비밀번호", "No results found": "", - "No source available": "", + "No source available": "사용 가능한 소스 없음", "Not factually correct": "", "Not sure what to add?": "추가할 것이 궁금하세요?", "Not sure what to write? Switch to": "무엇을 쓸지 모르겠나요? 전환하세요.", @@ -407,7 +407,7 @@ "Sign Out": "로그아웃", "Sign up": "가입", "Signing in": "", - "Source": "", + "Source": "출처", "Speech recognition error: {{error}}": "음성 인식 오류: {{error}}", "Speech-to-Text Engine": "음성-텍스트 엔진", "SpeechRecognition API is not supported in this browser.": "이 브라우저에서는 SpeechRecognition API를 지원하지 않습니다.", diff --git a/src/lib/i18n/locales/nl-NL/translation.json b/src/lib/i18n/locales/nl-NL/translation.json index a8a273f33..93d870d9d 100644 --- a/src/lib/i18n/locales/nl-NL/translation.json +++ b/src/lib/i18n/locales/nl-NL/translation.json @@ -76,8 +76,8 @@ "Chunk Overlap": "Chunk Overlap", "Chunk Params": "Chunk Params", "Chunk Size": "Chunk Grootte", - "Citation": "", - "Click here for help.": "Klik hier voor help.", + "Citation": "Citaat", + "Click here for help.": "Klik hier voor hulp.", "Click here to": "", "Click here to check other modelfiles.": "Klik hier om andere modelfiles te controleren.", "Click here to select": "Klik hier om te selecteren", @@ -285,7 +285,7 @@ "New Chat": "Nieuwe Chat", "New Password": "Nieuw Wachtwoord", "No results found": "", - "No source available": "", + "No source available": "Geen bron beschikbaar", "Not factually correct": "", "Not sure what to add?": "Niet zeker wat toe te voegen?", "Not sure what to write? Switch to": "Niet zeker wat te schrijven? Schakel over naar", @@ -407,7 +407,7 @@ "Sign Out": "Uitloggen", "Sign up": "Registreren", "Signing in": "", - "Source": "", + "Source": "Bron", "Speech recognition error: {{error}}": "Spraakherkenning fout: {{error}}", "Speech-to-Text Engine": "Spraak-naar-tekst Engine", "SpeechRecognition API is not supported in this browser.": "SpeechRecognition API wordt niet ondersteund in deze browser.", diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index cefa2f03c..154879ad9 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Zachodzenie bloku", "Chunk Params": "Parametry bloku", "Chunk Size": "Rozmiar bloku", - "Citation": "", + "Citation": "Cytat", "Click here for help.": "Kliknij tutaj, aby uzyskać pomoc.", "Click here to": "", "Click here to check other modelfiles.": "Kliknij tutaj, aby sprawdzić inne pliki modelowe.", @@ -285,7 +285,7 @@ "New Chat": "Nowy czat", "New Password": "Nowe hasło", "No results found": "", - "No source available": "", + "No source available": "Brak dostępnego źródła", "Not factually correct": "", "Not sure what to add?": "Nie wiesz, co dodać?", "Not sure what to write? Switch to": "Nie wiesz, co napisać? Przełącz się na", @@ -407,7 +407,7 @@ "Sign Out": "Wyloguj się", "Sign up": "Zarejestruj się", "Signing in": "", - "Source": "", + "Source": "Źródło", "Speech recognition error: {{error}}": "Błąd rozpoznawania mowy: {{error}}", "Speech-to-Text Engine": "Silnik mowy na tekst", "SpeechRecognition API is not supported in this browser.": "API Rozpoznawania Mowy nie jest obsługiwane w tej przeglądarce.", diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index 4d63439c3..9b8d6bcb5 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Sobreposição de Fragmento", "Chunk Params": "Parâmetros de Fragmento", "Chunk Size": "Tamanho do Fragmento", - "Citation": "", + "Citation": "Citação", "Click here for help.": "Clique aqui para obter ajuda.", "Click here to": "", "Click here to check other modelfiles.": "Clique aqui para verificar outros arquivos de modelo.", @@ -285,7 +285,7 @@ "New Chat": "Novo Bate-papo", "New Password": "Nova Senha", "No results found": "", - "No source available": "", + "No source available": "Nenhuma fonte disponível", "Not factually correct": "", "Not sure what to add?": "Não tem certeza do que adicionar?", "Not sure what to write? Switch to": "Não tem certeza do que escrever? Mude para", @@ -407,7 +407,7 @@ "Sign Out": "Sair", "Sign up": "Inscrever-se", "Signing in": "", - "Source": "", + "Source": "Fonte", "Speech recognition error: {{error}}": "Erro de reconhecimento de fala: {{error}}", "Speech-to-Text Engine": "Mecanismo de Fala para Texto", "SpeechRecognition API is not supported in this browser.": "A API SpeechRecognition não é suportada neste navegador.", diff --git a/src/lib/i18n/locales/pt-PT/translation.json b/src/lib/i18n/locales/pt-PT/translation.json index e69a005f5..115b16b9c 100644 --- a/src/lib/i18n/locales/pt-PT/translation.json +++ b/src/lib/i18n/locales/pt-PT/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Sobreposição de Fragmento", "Chunk Params": "Parâmetros de Fragmento", "Chunk Size": "Tamanho do Fragmento", - "Citation": "", + "Citation": "Citação", "Click here for help.": "Clique aqui para obter ajuda.", "Click here to": "", "Click here to check other modelfiles.": "Clique aqui para verificar outros arquivos de modelo.", @@ -285,7 +285,7 @@ "New Chat": "Novo Bate-papo", "New Password": "Nova Senha", "No results found": "", - "No source available": "", + "No source available": "Nenhuma fonte disponível", "Not factually correct": "", "Not sure what to add?": "Não tem certeza do que adicionar?", "Not sure what to write? Switch to": "Não tem certeza do que escrever? Mude para", @@ -407,7 +407,7 @@ "Sign Out": "Sair", "Sign up": "Inscrever-se", "Signing in": "", - "Source": "", + "Source": "Fonte", "Speech recognition error: {{error}}": "Erro de reconhecimento de fala: {{error}}", "Speech-to-Text Engine": "Mecanismo de Fala para Texto", "SpeechRecognition API is not supported in this browser.": "A API SpeechRecognition não é suportada neste navegador.", diff --git a/src/lib/i18n/locales/ru-RU/translation.json b/src/lib/i18n/locales/ru-RU/translation.json index 1fd73121f..7ba3d95c9 100644 --- a/src/lib/i18n/locales/ru-RU/translation.json +++ b/src/lib/i18n/locales/ru-RU/translation.json @@ -76,8 +76,8 @@ "Chunk Overlap": "Перекрытие фрагментов", "Chunk Params": "Параметры фрагментов", "Chunk Size": "Размер фрагмента", - "Citation": "", - "Click here for help.": "Нажмите здесь для помощь.", + "Citation": "Цитата", + "Click here for help.": "Нажмите здесь для помощи.", "Click here to": "", "Click here to check other modelfiles.": "Нажмите тут чтобы проверить другие файлы моделей.", "Click here to select": "Нажмите тут чтобы выберите", @@ -285,7 +285,7 @@ "New Chat": "Новый чат", "New Password": "Новый пароль", "No results found": "", - "No source available": "", + "No source available": "Нет доступных источников", "Not factually correct": "", "Not sure what to add?": "Не уверены, что добавить?", "Not sure what to write? Switch to": "Не уверены, что написать? Переключитесь на", @@ -407,7 +407,7 @@ "Sign Out": "Выход", "Sign up": "зарегистрировать", "Signing in": "", - "Source": "", + "Source": "Источник", "Speech recognition error: {{error}}": "Ошибка распознавания речи: {{error}}", "Speech-to-Text Engine": "Система распознавания речи", "SpeechRecognition API is not supported in this browser.": "API распознавания речи не поддерживается в этом браузере.", diff --git a/src/lib/i18n/locales/sv-SE/translation.json b/src/lib/i18n/locales/sv-SE/translation.json index 2876fad18..e9da9cd6b 100644 --- a/src/lib/i18n/locales/sv-SE/translation.json +++ b/src/lib/i18n/locales/sv-SE/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Överlappning", "Chunk Params": "Chunk-parametrar", "Chunk Size": "Chunk-storlek", - "Citation": "", + "Citation": "Citat", "Click here for help.": "Klicka här för hjälp.", "Click here to": "", "Click here to check other modelfiles.": "Klicka här för att kontrollera andra modelfiler.", @@ -285,7 +285,7 @@ "New Chat": "Ny chatt", "New Password": "Nytt lösenord", "No results found": "", - "No source available": "", + "No source available": "Ingen tilgjengelig kilde", "Not factually correct": "", "Not sure what to add?": "Inte säker på vad du ska lägga till?", "Not sure what to write? Switch to": "Inte säker på vad du ska skriva? Växla till", @@ -407,7 +407,7 @@ "Sign Out": "Logga ut", "Sign up": "Registrera dig", "Signing in": "", - "Source": "", + "Source": "Källa", "Speech recognition error: {{error}}": "Fel vid taligenkänning: {{error}}", "Speech-to-Text Engine": "Tal-till-text-motor", "SpeechRecognition API is not supported in this browser.": "SpeechRecognition API stöds inte i denna webbläsare.", diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index 5510678ad..2bef0dc8f 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Chunk Çakışması", "Chunk Params": "Chunk Parametreleri", "Chunk Size": "Chunk Boyutu", - "Citation": "", + "Citation": "Alıntı", "Click here for help.": "Yardım için buraya tıklayın.", "Click here to": "", "Click here to check other modelfiles.": "Diğer model dosyalarını kontrol etmek için buraya tıklayın.", @@ -285,7 +285,7 @@ "New Chat": "Yeni Sohbet", "New Password": "Yeni Parola", "No results found": "", - "No source available": "", + "No source available": "Kaynak mevcut değil", "Not factually correct": "Gerçeklere göre doğru değil", "Not sure what to add?": "Ne ekleyeceğinizden emin değil misiniz?", "Not sure what to write? Switch to": "Ne yazacağınızdan emin değil misiniz? Şuraya geçin", @@ -407,7 +407,7 @@ "Sign Out": "Çıkış Yap", "Sign up": "Kaydol", "Signing in": "Oturum açma", - "Source": "", + "Source": "Kaynak", "Speech recognition error: {{error}}": "Konuşma tanıma hatası: {{error}}", "Speech-to-Text Engine": "Konuşmadan Metne Motoru", "SpeechRecognition API is not supported in this browser.": "SpeechRecognition API bu tarayıcıda desteklenmiyor.", diff --git a/src/lib/i18n/locales/vi-VN/translation.json b/src/lib/i18n/locales/vi-VN/translation.json index d9e5681f0..45146e354 100644 --- a/src/lib/i18n/locales/vi-VN/translation.json +++ b/src/lib/i18n/locales/vi-VN/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Chồng lấn (overlap)", "Chunk Params": "Cài đặt số lượng ký tự cho khối ký tự (chunk)", "Chunk Size": "Kích thước khối (size)", - "Citation": "", + "Citation": "Trích dẫn", "Click here for help.": "Bấm vào đây để được trợ giúp.", "Click here to": "", "Click here to check other modelfiles.": "Bấm vào đây để kiểm tra các tệp mô tả mô hình (modelfiles) khác.", @@ -285,7 +285,7 @@ "New Chat": "Tạo cuộc trò chuyện mới", "New Password": "Mật khẩu mới", "No results found": "", - "No source available": "", + "No source available": "Không có nguồn", "Not factually correct": "Không chính xác so với thực tế", "Not sure what to add?": "Không chắc phải thêm gì?", "Not sure what to write? Switch to": "Không chắc phải viết gì? Chuyển sang", @@ -407,7 +407,7 @@ "Sign Out": "Đăng xuất", "Sign up": "Đăng ký", "Signing in": "", - "Source": "", + "Source": "Nguồn", "Speech recognition error: {{error}}": "Lỗi nhận dạng giọng nói: {{error}}", "Speech-to-Text Engine": "Công cụ Nhận dạng Giọng nói", "SpeechRecognition API is not supported in this browser.": "Trình duyệt này không hỗ trợ API Nhận dạng Giọng nói.", diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index 1239b724b..91fab088d 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -43,7 +43,7 @@ "API keys": "", "API RPM": "API RPM", "April": "", - "Archive": "", + "Archive": "存档", "Archived Chats": "聊天记录存档", "are allowed - Activate this command by typing": "允许 - 通过输入来激活这个命令", "Are you sure?": "你确定吗?", @@ -76,7 +76,7 @@ "Chunk Overlap": "块重叠 (Chunk Overlap)", "Chunk Params": "块参数 (Chunk Params)", "Chunk Size": "块大小 (Chunk Size)", - "Citation": "", + "Citation": "引文", "Click here for help.": "点击这里获取帮助。", "Click here to": "", "Click here to check other modelfiles.": "点击这里检查其他模型文件。", @@ -97,11 +97,11 @@ "Context Length": "上下文长度", "Continue Response": "", "Conversation Mode": "对话模式", - "Copied shared chat URL to clipboard!": "", - "Copy": "", + "Copied shared chat URL to clipboard!": "已复制共享聊天 URL 到剪贴板!", + "Copy": "复制", "Copy last code block": "复制最后一个代码块", "Copy last response": "复制最后一次回复", - "Copy Link": "", + "Copy Link": "复制链接", "Copying to clipboard was successful!": "复制到剪贴板成功!", "Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "为以下查询创建一个简洁的、3-5 个词的短语作为标题,严格遵守 3-5 个词的限制并避免使用“标题”一词:", "Create a modelfile": "创建模型文件", @@ -127,13 +127,13 @@ "Default Prompt Suggestions": "默认提示词建议", "Default User Role": "默认用户角色", "delete": "删除", - "Delete": "", + "Delete": "删除", "Delete a model": "删除一个模型", "Delete chat": "删除聊天", - "Delete Chat": "", + "Delete Chat": "删除聊天", "Delete Chats": "删除聊天记录", "delete this link": "", - "Delete User": "", + "Delete User": "删除用户", "Deleted {{deleteModelTag}}": "已删除{{deleteModelTag}}", "Deleted {{tagName}}": "", "Description": "描述", @@ -150,13 +150,13 @@ "does not make any external connections, and your data stays securely on your locally hosted server.": "不进行任何外部连接,您的数据安全地存储在您的本地服务器上。", "Don't Allow": "不允许", "Don't have an account?": "没有账户?", - "Don't like the style": "", - "Download": "", - "Download canceled": "", + "Don't like the style": "不喜欢这个风格", + "Download": "下载", + "Download canceled": "下载已取消", "Download Database": "下载数据库", "Drop any files here to add to the conversation": "拖动文件到此处以添加到对话中", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "例如 '30s','10m'。有效的时间单位是's', 'm', 'h'。", - "Edit": "", + "Edit": "编辑", "Edit Doc": "编辑文档", "Edit User": "编辑用户", "Email": "电子邮件", @@ -187,17 +187,17 @@ "Enter Your Email": "输入您的电子邮件", "Enter Your Full Name": "输入您的全名", "Enter Your Password": "输入您的密码", - "Enter Your Role": "", + "Enter Your Role": "输入您的角色", "Experimental": "实验性", "Export All Chats (All Users)": "导出所有聊天(所有用户)", "Export Chats": "导出聊天", "Export Documents Mapping": "导出文档映射", "Export Modelfiles": "导出模型文件", "Export Prompts": "导出提示词", - "Failed to create API Key.": "", + "Failed to create API Key.": "无法创建 API 密钥。", "Failed to read clipboard contents": "无法读取剪贴板内容", "February": "", - "Feel free to add specific details": "", + "Feel free to add specific details": "请随意添加具体细节", "File Mode": "文件模式", "File not found.": "文件未找到。", "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "", @@ -209,11 +209,11 @@ "Full Screen Mode": "全屏模式", "General": "通用", "General Settings": "通用设置", - "Generation Info": "", + "Generation Info": "生成信息", "Good Response": "", "has no conversations.": "", "Hello, {{name}}": "你好,{{name}}", - "Help": "", + "Help": "帮助", "Hide": "隐藏", "Hide Additional Params": "隐藏额外参数", "How can I help you today?": "我今天能帮你做什么?", @@ -227,9 +227,9 @@ "Import Modelfiles": "导入模型文件", "Import Prompts": "导入提示", "Include `--api` flag when running stable-diffusion-webui": "运行 stable-diffusion-webui 时包含 `--api` 标志", - "Input commands": "", + "Input commands": "输入命令", "Interface": "界面", - "Invalid Tag": "", + "Invalid Tag": "无效标签", "January": "", "join our Discord for help.": "加入我们的 Discord 寻求帮助。", "JSON": "JSON", @@ -240,7 +240,7 @@ "Keep Alive": "保持活动", "Keyboard shortcuts": "键盘快捷键", "Language": "语言", - "Last Active": "", + "Last Active": "最后活跃", "Light": "浅色", "Listening...": "监听中...", "LLMs can make mistakes. Verify important information.": "LLM 可能会生成错误信息,请验证重要信息。", @@ -285,7 +285,7 @@ "New Chat": "新聊天", "New Password": "新密码", "No results found": "", - "No source available": "", + "No source available": "没有可用来源", "Not factually correct": "", "Not sure what to add?": "不确定要添加什么?", "Not sure what to write? Switch to": "不确定写什么?切换到", @@ -295,7 +295,7 @@ "October": "", "Off": "关闭", "Okay, Let's Go!": "好的,我们开始吧!", - "OLED Dark": "", + "OLED Dark": "暗黑色", "Ollama": "", "Ollama Base URL": "Ollama 基础 URL", "Ollama Version": "Ollama 版本", @@ -325,10 +325,10 @@ "Permission denied when accessing microphone: {{error}}": "访问麦克风时权限被拒绝:{{error}}", "Plain text (.txt)": "", "Playground": "AI 对话游乐场", - "Positive attitude": "", + "Positive attitude": "积极态度", "Previous 30 days": "", "Previous 7 days": "", - "Profile Image": "", + "Profile Image": "用户头像", "Prompt": "", "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "", "Prompt Content": "提示词内容", @@ -344,9 +344,9 @@ "Record voice": "录音", "Redirecting you to OpenWebUI Community": "正在将您重定向到 OpenWebUI 社区", "Refused when it shouldn't have": "", - "Regenerate": "", + "Regenerate": "重新生成", "Release Notes": "发布说明", - "Remove": "", + "Remove": "移除", "Remove Model": "", "Rename": "", "Repeat Last N": "重复最后 N 次", @@ -394,8 +394,8 @@ "Set Voice": "设置声音", "Settings": "设置", "Settings saved successfully!": "设置已保存", - "Share": "", - "Share Chat": "", + "Share": "分享", + "Share Chat": "分享聊天", "Share to OpenWebUI Community": "分享到 OpenWebUI 社区", "short-summary": "简短总结", "Show": "显示", @@ -406,8 +406,8 @@ "Sign in": "登录", "Sign Out": "登出", "Sign up": "注册", - "Signing in": "", - "Source": "", + "Signing in": "正在登录", + "Source": "来源", "Speech recognition error: {{error}}": "语音识别错误:{{error}}", "Speech-to-Text Engine": "语音转文字引擎", "SpeechRecognition API is not supported in this browser.": "此浏览器不支持 SpeechRecognition API。", @@ -473,9 +473,9 @@ "Version": "版本", "Warning: If you update or change your embedding model, you will need to re-import all documents.": "", "Web": "网页", - "Web Loader Settings": "", - "Web Params": "", - "Webhook URL": "", + "Web Loader Settings": "Web 加载器设置", + "Web Params": "Web 参数", + "Webhook URL": "Webhook URL", "WebUI Add-ons": "WebUI 插件", "WebUI Settings": "WebUI 设置", "WebUI will make requests to": "WebUI 将请求", @@ -486,10 +486,10 @@ "Write a summary in 50 words that summarizes [topic or keyword].": "用 50 个字写一个总结 [主题或关键词]。", "Yesterday": "", "You": "你", - "You have no archived conversations.": "", + "You have no archived conversations.": "你没有存档的对话。", "You have shared this chat": "", "You're a helpful assistant.": "你是一个有帮助的助手。", "You're now logged in.": "已登录。", "Youtube": "", - "Youtube Loader Settings": "" -} + "Youtube Loader Settings": "Youtube 加载器设置" +} \ No newline at end of file diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index 50a5c3275..3169966dc 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -76,7 +76,7 @@ "Chunk Overlap": "Chunk Overlap", "Chunk Params": "Chunk 參數", "Chunk Size": "Chunk 大小", - "Citation": "", + "Citation": "引文", "Click here for help.": "點擊這裡尋找幫助。", "Click here to": "", "Click here to check other modelfiles.": "點擊這裡檢查其他 Modelfiles。", @@ -285,7 +285,7 @@ "New Chat": "新增聊天", "New Password": "新密碼", "No results found": "", - "No source available": "", + "No source available": "沒有可用的來源", "Not factually correct": "", "Not sure what to add?": "不確定要新增什麼嗎?", "Not sure what to write? Switch to": "不確定要寫什麼?切換到", @@ -381,7 +381,7 @@ "Select model": "", "Send a Message": "傳送訊息", "Send message": "傳送訊息", - "September": "", + "September": "九月", "Server connection verified": "已驗證伺服器連線", "Set as default": "設為預設", "Set Default Model": "設定預設模型", @@ -394,8 +394,8 @@ "Set Voice": "設定語音", "Settings": "設定", "Settings saved successfully!": "成功儲存設定", - "Share": "", - "Share Chat": "", + "Share": "分享", + "Share Chat": "分享聊天", "Share to OpenWebUI Community": "分享到 OpenWebUI 社群", "short-summary": "簡短摘要", "Show": "顯示", @@ -406,8 +406,8 @@ "Sign in": "登入", "Sign Out": "登出", "Sign up": "註冊", - "Signing in": "", - "Source": "", + "Signing in": "正在登入", + "Source": "來源", "Speech recognition error: {{error}}": "語音識別錯誤:{{error}}", "Speech-to-Text Engine": "語音轉文字引擎", "SpeechRecognition API is not supported in this browser.": "此瀏覽器不支持 SpeechRecognition API。", @@ -417,7 +417,7 @@ "Subtitle (e.g. about the Roman Empire)": "", "Success": "成功", "Successfully updated.": "更新成功。", - "Suggested": "", + "Suggested": "建議", "Sync All": "全部同步", "System": "系統", "System Prompt": "系統提示詞", From 058eb765687a542e4ce542d5fc8aea921ef85035 Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Fri, 10 May 2024 13:36:10 +0800 Subject: [PATCH 05/29] feat: save UI config changes to config.json --- backend/apps/audio/main.py | 31 ++- backend/apps/images/main.py | 105 ++++---- backend/apps/ollama/main.py | 56 +++-- backend/apps/openai/main.py | 47 ++-- backend/apps/rag/main.py | 237 ++++++++++-------- backend/apps/web/main.py | 8 +- backend/apps/web/routers/auths.py | 38 +-- backend/apps/web/routers/configs.py | 9 +- backend/apps/web/routers/users.py | 8 +- backend/config.py | 366 ++++++++++++++++++++-------- backend/main.py | 42 ++-- 11 files changed, 611 insertions(+), 336 deletions(-) diff --git a/backend/apps/audio/main.py b/backend/apps/audio/main.py index 87732d7bc..c3dc6a2c4 100644 --- a/backend/apps/audio/main.py +++ b/backend/apps/audio/main.py @@ -45,6 +45,8 @@ from config import ( AUDIO_OPENAI_API_KEY, AUDIO_OPENAI_API_MODEL, AUDIO_OPENAI_API_VOICE, + config_get, + config_set, ) log = logging.getLogger(__name__) @@ -83,10 +85,10 @@ class OpenAIConfigUpdateForm(BaseModel): @app.get("/config") async def get_openai_config(user=Depends(get_admin_user)): return { - "OPENAI_API_BASE_URL": app.state.OPENAI_API_BASE_URL, - "OPENAI_API_KEY": app.state.OPENAI_API_KEY, - "OPENAI_API_MODEL": app.state.OPENAI_API_MODEL, - "OPENAI_API_VOICE": app.state.OPENAI_API_VOICE, + "OPENAI_API_BASE_URL": config_get(app.state.OPENAI_API_BASE_URL), + "OPENAI_API_KEY": config_get(app.state.OPENAI_API_KEY), + "OPENAI_API_MODEL": config_get(app.state.OPENAI_API_MODEL), + "OPENAI_API_VOICE": config_get(app.state.OPENAI_API_VOICE), } @@ -97,17 +99,22 @@ async def update_openai_config( if form_data.key == "": raise HTTPException(status_code=400, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND) - app.state.OPENAI_API_BASE_URL = form_data.url - app.state.OPENAI_API_KEY = form_data.key - app.state.OPENAI_API_MODEL = form_data.model - app.state.OPENAI_API_VOICE = form_data.speaker + config_set(app.state.OPENAI_API_BASE_URL, form_data.url) + config_set(app.state.OPENAI_API_KEY, form_data.key) + config_set(app.state.OPENAI_API_MODEL, form_data.model) + config_set(app.state.OPENAI_API_VOICE, form_data.speaker) + + app.state.OPENAI_API_BASE_URL.save() + app.state.OPENAI_API_KEY.save() + app.state.OPENAI_API_MODEL.save() + app.state.OPENAI_API_VOICE.save() return { "status": True, - "OPENAI_API_BASE_URL": app.state.OPENAI_API_BASE_URL, - "OPENAI_API_KEY": app.state.OPENAI_API_KEY, - "OPENAI_API_MODEL": app.state.OPENAI_API_MODEL, - "OPENAI_API_VOICE": app.state.OPENAI_API_VOICE, + "OPENAI_API_BASE_URL": config_get(app.state.OPENAI_API_BASE_URL), + "OPENAI_API_KEY": config_get(app.state.OPENAI_API_KEY), + "OPENAI_API_MODEL": config_get(app.state.OPENAI_API_MODEL), + "OPENAI_API_VOICE": config_get(app.state.OPENAI_API_VOICE), } diff --git a/backend/apps/images/main.py b/backend/apps/images/main.py index f45cf0d12..8ebfb0446 100644 --- a/backend/apps/images/main.py +++ b/backend/apps/images/main.py @@ -42,6 +42,8 @@ from config import ( IMAGE_GENERATION_MODEL, IMAGE_SIZE, IMAGE_STEPS, + config_get, + config_set, ) @@ -79,7 +81,10 @@ app.state.IMAGE_STEPS = IMAGE_STEPS @app.get("/config") async def get_config(request: Request, user=Depends(get_admin_user)): - return {"engine": app.state.ENGINE, "enabled": app.state.ENABLED} + return { + "engine": config_get(app.state.ENGINE), + "enabled": config_get(app.state.ENABLED), + } class ConfigUpdateForm(BaseModel): @@ -89,9 +94,12 @@ class ConfigUpdateForm(BaseModel): @app.post("/config/update") async def update_config(form_data: ConfigUpdateForm, user=Depends(get_admin_user)): - app.state.ENGINE = form_data.engine - app.state.ENABLED = form_data.enabled - return {"engine": app.state.ENGINE, "enabled": app.state.ENABLED} + config_set(app.state.ENGINE, form_data.engine) + config_set(app.state.ENABLED, form_data.enabled) + return { + "engine": config_get(app.state.ENGINE), + "enabled": config_get(app.state.ENABLED), + } class EngineUrlUpdateForm(BaseModel): @@ -102,8 +110,8 @@ class EngineUrlUpdateForm(BaseModel): @app.get("/url") async def get_engine_url(user=Depends(get_admin_user)): return { - "AUTOMATIC1111_BASE_URL": app.state.AUTOMATIC1111_BASE_URL, - "COMFYUI_BASE_URL": app.state.COMFYUI_BASE_URL, + "AUTOMATIC1111_BASE_URL": config_get(app.state.AUTOMATIC1111_BASE_URL), + "COMFYUI_BASE_URL": config_get(app.state.COMFYUI_BASE_URL), } @@ -113,29 +121,29 @@ async def update_engine_url( ): if form_data.AUTOMATIC1111_BASE_URL == None: - app.state.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL + config_set(app.state.AUTOMATIC1111_BASE_URL, config_get(AUTOMATIC1111_BASE_URL)) else: url = form_data.AUTOMATIC1111_BASE_URL.strip("/") try: r = requests.head(url) - app.state.AUTOMATIC1111_BASE_URL = url + config_set(app.state.AUTOMATIC1111_BASE_URL, url) except Exception as e: raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) if form_data.COMFYUI_BASE_URL == None: - app.state.COMFYUI_BASE_URL = COMFYUI_BASE_URL + config_set(app.state.COMFYUI_BASE_URL, COMFYUI_BASE_URL) else: url = form_data.COMFYUI_BASE_URL.strip("/") try: r = requests.head(url) - app.state.COMFYUI_BASE_URL = url + config_set(app.state.COMFYUI_BASE_URL, url) except Exception as e: raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) return { - "AUTOMATIC1111_BASE_URL": app.state.AUTOMATIC1111_BASE_URL, - "COMFYUI_BASE_URL": app.state.COMFYUI_BASE_URL, + "AUTOMATIC1111_BASE_URL": config_get(app.state.AUTOMATIC1111_BASE_URL), + "COMFYUI_BASE_URL": config_get(app.state.COMFYUI_BASE_URL), "status": True, } @@ -148,8 +156,8 @@ class OpenAIConfigUpdateForm(BaseModel): @app.get("/openai/config") async def get_openai_config(user=Depends(get_admin_user)): return { - "OPENAI_API_BASE_URL": app.state.OPENAI_API_BASE_URL, - "OPENAI_API_KEY": app.state.OPENAI_API_KEY, + "OPENAI_API_BASE_URL": config_get(app.state.OPENAI_API_BASE_URL), + "OPENAI_API_KEY": config_get(app.state.OPENAI_API_KEY), } @@ -160,13 +168,13 @@ async def update_openai_config( if form_data.key == "": raise HTTPException(status_code=400, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND) - app.state.OPENAI_API_BASE_URL = form_data.url - app.state.OPENAI_API_KEY = form_data.key + config_set(app.state.OPENAI_API_BASE_URL, form_data.url) + config_set(app.state.OPENAI_API_KEY, form_data.key) return { "status": True, - "OPENAI_API_BASE_URL": app.state.OPENAI_API_BASE_URL, - "OPENAI_API_KEY": app.state.OPENAI_API_KEY, + "OPENAI_API_BASE_URL": config_get(app.state.OPENAI_API_BASE_URL), + "OPENAI_API_KEY": config_get(app.state.OPENAI_API_KEY), } @@ -176,7 +184,7 @@ class ImageSizeUpdateForm(BaseModel): @app.get("/size") async def get_image_size(user=Depends(get_admin_user)): - return {"IMAGE_SIZE": app.state.IMAGE_SIZE} + return {"IMAGE_SIZE": config_get(app.state.IMAGE_SIZE)} @app.post("/size/update") @@ -185,9 +193,9 @@ async def update_image_size( ): pattern = r"^\d+x\d+$" # Regular expression pattern if re.match(pattern, form_data.size): - app.state.IMAGE_SIZE = form_data.size + config_set(app.state.IMAGE_SIZE, form_data.size) return { - "IMAGE_SIZE": app.state.IMAGE_SIZE, + "IMAGE_SIZE": config_get(app.state.IMAGE_SIZE), "status": True, } else: @@ -203,7 +211,7 @@ class ImageStepsUpdateForm(BaseModel): @app.get("/steps") async def get_image_size(user=Depends(get_admin_user)): - return {"IMAGE_STEPS": app.state.IMAGE_STEPS} + return {"IMAGE_STEPS": config_get(app.state.IMAGE_STEPS)} @app.post("/steps/update") @@ -211,9 +219,9 @@ async def update_image_size( form_data: ImageStepsUpdateForm, user=Depends(get_admin_user) ): if form_data.steps >= 0: - app.state.IMAGE_STEPS = form_data.steps + config_set(app.state.IMAGE_STEPS, form_data.steps) return { - "IMAGE_STEPS": app.state.IMAGE_STEPS, + "IMAGE_STEPS": config_get(app.state.IMAGE_STEPS), "status": True, } else: @@ -263,15 +271,25 @@ def get_models(user=Depends(get_current_user)): async def get_default_model(user=Depends(get_admin_user)): try: if app.state.ENGINE == "openai": - return {"model": app.state.MODEL if app.state.MODEL else "dall-e-2"} + return { + "model": ( + config_get(app.state.MODEL) + if config_get(app.state.MODEL) + else "dall-e-2" + ) + } elif app.state.ENGINE == "comfyui": - return {"model": app.state.MODEL if app.state.MODEL else ""} + return { + "model": ( + config_get(app.state.MODEL) if config_get(app.state.MODEL) else "" + ) + } else: r = requests.get(url=f"{app.state.AUTOMATIC1111_BASE_URL}/sdapi/v1/options") options = r.json() return {"model": options["sd_model_checkpoint"]} except Exception as e: - app.state.ENABLED = False + config_set(app.state.ENABLED, False) raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) @@ -280,12 +298,9 @@ class UpdateModelForm(BaseModel): def set_model_handler(model: str): - if app.state.ENGINE == "openai": - app.state.MODEL = model - return app.state.MODEL - if app.state.ENGINE == "comfyui": - app.state.MODEL = model - return app.state.MODEL + if app.state.ENGINE in ["openai", "comfyui"]: + config_set(app.state.MODEL, model) + return config_get(app.state.MODEL) else: r = requests.get(url=f"{app.state.AUTOMATIC1111_BASE_URL}/sdapi/v1/options") options = r.json() @@ -382,7 +397,7 @@ def generate_image( user=Depends(get_current_user), ): - width, height = tuple(map(int, app.state.IMAGE_SIZE.split("x"))) + width, height = tuple(map(int, config_get(app.state.IMAGE_SIZE).split("x"))) r = None try: @@ -396,7 +411,11 @@ def generate_image( "model": app.state.MODEL if app.state.MODEL != "" else "dall-e-2", "prompt": form_data.prompt, "n": form_data.n, - "size": form_data.size if form_data.size else app.state.IMAGE_SIZE, + "size": ( + form_data.size + if form_data.size + else config_get(app.state.IMAGE_SIZE) + ), "response_format": "b64_json", } @@ -430,19 +449,19 @@ def generate_image( "n": form_data.n, } - if app.state.IMAGE_STEPS != None: - data["steps"] = app.state.IMAGE_STEPS + if config_get(app.state.IMAGE_STEPS) is not None: + data["steps"] = config_get(app.state.IMAGE_STEPS) - if form_data.negative_prompt != None: + if form_data.negative_prompt is not None: data["negative_prompt"] = form_data.negative_prompt data = ImageGenerationPayload(**data) res = comfyui_generate_image( - app.state.MODEL, + config_get(app.state.MODEL), data, user.id, - app.state.COMFYUI_BASE_URL, + config_get(app.state.COMFYUI_BASE_URL), ) log.debug(f"res: {res}") @@ -469,10 +488,10 @@ def generate_image( "height": height, } - if app.state.IMAGE_STEPS != None: - data["steps"] = app.state.IMAGE_STEPS + if config_get(app.state.IMAGE_STEPS) is not None: + data["steps"] = config_get(app.state.IMAGE_STEPS) - if form_data.negative_prompt != None: + if form_data.negative_prompt is not None: data["negative_prompt"] = form_data.negative_prompt r = requests.post( diff --git a/backend/apps/ollama/main.py b/backend/apps/ollama/main.py index 042d0336d..7dfadbb0c 100644 --- a/backend/apps/ollama/main.py +++ b/backend/apps/ollama/main.py @@ -46,6 +46,8 @@ from config import ( ENABLE_MODEL_FILTER, MODEL_FILTER_LIST, UPLOAD_DIR, + config_set, + config_get, ) from utils.misc import calculate_sha256 @@ -96,7 +98,7 @@ async def get_status(): @app.get("/urls") async def get_ollama_api_urls(user=Depends(get_admin_user)): - return {"OLLAMA_BASE_URLS": app.state.OLLAMA_BASE_URLS} + return {"OLLAMA_BASE_URLS": config_get(app.state.OLLAMA_BASE_URLS)} class UrlUpdateForm(BaseModel): @@ -105,10 +107,10 @@ class UrlUpdateForm(BaseModel): @app.post("/urls/update") async def update_ollama_api_url(form_data: UrlUpdateForm, user=Depends(get_admin_user)): - app.state.OLLAMA_BASE_URLS = form_data.urls + config_set(app.state.OLLAMA_BASE_URLS, form_data.urls) log.info(f"app.state.OLLAMA_BASE_URLS: {app.state.OLLAMA_BASE_URLS}") - return {"OLLAMA_BASE_URLS": app.state.OLLAMA_BASE_URLS} + return {"OLLAMA_BASE_URLS": config_get(app.state.OLLAMA_BASE_URLS)} @app.get("/cancel/{request_id}") @@ -153,7 +155,9 @@ def merge_models_lists(model_lists): async def get_all_models(): log.info("get_all_models()") - tasks = [fetch_url(f"{url}/api/tags") for url in app.state.OLLAMA_BASE_URLS] + tasks = [ + fetch_url(f"{url}/api/tags") for url in config_get(app.state.OLLAMA_BASE_URLS) + ] responses = await asyncio.gather(*tasks) models = { @@ -179,14 +183,15 @@ async def get_ollama_tags( if user.role == "user": models["models"] = list( filter( - lambda model: model["name"] in app.state.MODEL_FILTER_LIST, + lambda model: model["name"] + in config_get(app.state.MODEL_FILTER_LIST), models["models"], ) ) return models return models else: - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] try: r = requests.request(method="GET", url=f"{url}/api/tags") r.raise_for_status() @@ -216,7 +221,10 @@ async def get_ollama_versions(url_idx: Optional[int] = None): if url_idx == None: # returns lowest version - tasks = [fetch_url(f"{url}/api/version") for url in app.state.OLLAMA_BASE_URLS] + tasks = [ + fetch_url(f"{url}/api/version") + for url in config_get(app.state.OLLAMA_BASE_URLS) + ] responses = await asyncio.gather(*tasks) responses = list(filter(lambda x: x is not None, responses)) @@ -235,7 +243,7 @@ async def get_ollama_versions(url_idx: Optional[int] = None): detail=ERROR_MESSAGES.OLLAMA_NOT_FOUND, ) else: - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] try: r = requests.request(method="GET", url=f"{url}/api/version") r.raise_for_status() @@ -267,7 +275,7 @@ class ModelNameForm(BaseModel): async def pull_model( form_data: ModelNameForm, url_idx: int = 0, user=Depends(get_admin_user) ): - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") r = None @@ -355,7 +363,7 @@ async def push_model( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.name), ) - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.debug(f"url: {url}") r = None @@ -417,7 +425,7 @@ async def create_model( form_data: CreateModelForm, url_idx: int = 0, user=Depends(get_admin_user) ): log.debug(f"form_data: {form_data}") - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") r = None @@ -490,7 +498,7 @@ async def copy_model( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.source), ) - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") try: @@ -537,7 +545,7 @@ async def delete_model( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.name), ) - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") try: @@ -577,7 +585,7 @@ async def show_model_info(form_data: ModelNameForm, user=Depends(get_verified_us ) url_idx = random.choice(app.state.MODELS[form_data.name]["urls"]) - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") try: @@ -634,7 +642,7 @@ async def generate_embeddings( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") try: @@ -684,7 +692,7 @@ def generate_ollama_embeddings( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") try: @@ -753,7 +761,7 @@ async def generate_completion( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") r = None @@ -856,7 +864,7 @@ async def generate_chat_completion( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") r = None @@ -965,7 +973,7 @@ async def generate_openai_chat_completion( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] log.info(f"url: {url}") r = None @@ -1064,7 +1072,7 @@ async def get_openai_models( } else: - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] try: r = requests.request(method="GET", url=f"{url}/api/tags") r.raise_for_status() @@ -1198,7 +1206,7 @@ async def download_model( if url_idx == None: url_idx = 0 - url = app.state.OLLAMA_BASE_URLS[url_idx] + url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] file_name = parse_huggingface_url(form_data.url) @@ -1217,7 +1225,7 @@ async def download_model( def upload_model(file: UploadFile = File(...), url_idx: Optional[int] = None): if url_idx == None: url_idx = 0 - ollama_url = app.state.OLLAMA_BASE_URLS[url_idx] + ollama_url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] file_path = f"{UPLOAD_DIR}/{file.filename}" @@ -1282,7 +1290,7 @@ def upload_model(file: UploadFile = File(...), url_idx: Optional[int] = None): # async def upload_model(file: UploadFile = File(), url_idx: Optional[int] = None): # if url_idx == None: # url_idx = 0 -# url = app.state.OLLAMA_BASE_URLS[url_idx] +# url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] # file_location = os.path.join(UPLOAD_DIR, file.filename) # total_size = file.size @@ -1319,7 +1327,7 @@ def upload_model(file: UploadFile = File(...), url_idx: Optional[int] = None): async def deprecated_proxy( path: str, request: Request, user=Depends(get_verified_user) ): - url = app.state.OLLAMA_BASE_URLS[0] + url = config_get(app.state.OLLAMA_BASE_URLS)[0] target_url = f"{url}/{path}" body = await request.body() diff --git a/backend/apps/openai/main.py b/backend/apps/openai/main.py index b5d1e68d6..36fed104c 100644 --- a/backend/apps/openai/main.py +++ b/backend/apps/openai/main.py @@ -26,6 +26,8 @@ from config import ( CACHE_DIR, ENABLE_MODEL_FILTER, MODEL_FILTER_LIST, + config_set, + config_get, ) from typing import List, Optional @@ -75,32 +77,34 @@ class KeysUpdateForm(BaseModel): @app.get("/urls") async def get_openai_urls(user=Depends(get_admin_user)): - return {"OPENAI_API_BASE_URLS": app.state.OPENAI_API_BASE_URLS} + return {"OPENAI_API_BASE_URLS": config_get(app.state.OPENAI_API_BASE_URLS)} @app.post("/urls/update") async def update_openai_urls(form_data: UrlsUpdateForm, user=Depends(get_admin_user)): await get_all_models() - app.state.OPENAI_API_BASE_URLS = form_data.urls - return {"OPENAI_API_BASE_URLS": app.state.OPENAI_API_BASE_URLS} + config_set(app.state.OPENAI_API_BASE_URLS, form_data.urls) + return {"OPENAI_API_BASE_URLS": config_get(app.state.OPENAI_API_BASE_URLS)} @app.get("/keys") async def get_openai_keys(user=Depends(get_admin_user)): - return {"OPENAI_API_KEYS": app.state.OPENAI_API_KEYS} + return {"OPENAI_API_KEYS": config_get(app.state.OPENAI_API_KEYS)} @app.post("/keys/update") async def update_openai_key(form_data: KeysUpdateForm, user=Depends(get_admin_user)): - app.state.OPENAI_API_KEYS = form_data.keys - return {"OPENAI_API_KEYS": app.state.OPENAI_API_KEYS} + config_set(app.state.OPENAI_API_KEYS, form_data.keys) + return {"OPENAI_API_KEYS": config_get(app.state.OPENAI_API_KEYS)} @app.post("/audio/speech") async def speech(request: Request, user=Depends(get_verified_user)): idx = None try: - idx = app.state.OPENAI_API_BASE_URLS.index("https://api.openai.com/v1") + idx = config_get(app.state.OPENAI_API_BASE_URLS).index( + "https://api.openai.com/v1" + ) body = await request.body() name = hashlib.sha256(body).hexdigest() @@ -114,13 +118,15 @@ async def speech(request: Request, user=Depends(get_verified_user)): return FileResponse(file_path) headers = {} - headers["Authorization"] = f"Bearer {app.state.OPENAI_API_KEYS[idx]}" + headers["Authorization"] = ( + f"Bearer {config_get(app.state.OPENAI_API_KEYS)[idx]}" + ) headers["Content-Type"] = "application/json" r = None try: r = requests.post( - url=f"{app.state.OPENAI_API_BASE_URLS[idx]}/audio/speech", + url=f"{config_get(app.state.OPENAI_API_BASE_URLS)[idx]}/audio/speech", data=body, headers=headers, stream=True, @@ -180,7 +186,8 @@ def merge_models_lists(model_lists): [ {**model, "urlIdx": idx} for model in models - if "api.openai.com" not in app.state.OPENAI_API_BASE_URLS[idx] + if "api.openai.com" + not in config_get(app.state.OPENAI_API_BASE_URLS)[idx] or "gpt" in model["id"] ] ) @@ -191,12 +198,15 @@ def merge_models_lists(model_lists): async def get_all_models(): log.info("get_all_models()") - if len(app.state.OPENAI_API_KEYS) == 1 and app.state.OPENAI_API_KEYS[0] == "": + if ( + len(config_get(app.state.OPENAI_API_KEYS)) == 1 + and config_get(app.state.OPENAI_API_KEYS)[0] == "" + ): models = {"data": []} else: tasks = [ - fetch_url(f"{url}/models", app.state.OPENAI_API_KEYS[idx]) - for idx, url in enumerate(app.state.OPENAI_API_BASE_URLS) + fetch_url(f"{url}/models", config_get(app.state.OPENAI_API_KEYS)[idx]) + for idx, url in enumerate(config_get(app.state.OPENAI_API_BASE_URLS)) ] responses = await asyncio.gather(*tasks) @@ -228,18 +238,19 @@ async def get_all_models(): async def get_models(url_idx: Optional[int] = None, user=Depends(get_current_user)): if url_idx == None: models = await get_all_models() - if app.state.ENABLE_MODEL_FILTER: + if config_get(app.state.ENABLE_MODEL_FILTER): if user.role == "user": models["data"] = list( filter( - lambda model: model["id"] in app.state.MODEL_FILTER_LIST, + lambda model: model["id"] + in config_get(app.state.MODEL_FILTER_LIST), models["data"], ) ) return models return models else: - url = app.state.OPENAI_API_BASE_URLS[url_idx] + url = config_get(app.state.OPENAI_API_BASE_URLS)[url_idx] r = None @@ -303,8 +314,8 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)): except json.JSONDecodeError as e: log.error("Error loading request body into a dictionary:", e) - url = app.state.OPENAI_API_BASE_URLS[idx] - key = app.state.OPENAI_API_KEYS[idx] + url = config_get(app.state.OPENAI_API_BASE_URLS)[idx] + key = config_get(app.state.OPENAI_API_KEYS)[idx] target_url = f"{url}/{path}" diff --git a/backend/apps/rag/main.py b/backend/apps/rag/main.py index 2e2a8e209..f05447a66 100644 --- a/backend/apps/rag/main.py +++ b/backend/apps/rag/main.py @@ -93,6 +93,8 @@ from config import ( RAG_TEMPLATE, ENABLE_RAG_LOCAL_WEB_FETCH, YOUTUBE_LOADER_LANGUAGE, + config_set, + config_get, ) from constants import ERROR_MESSAGES @@ -133,7 +135,7 @@ def update_embedding_model( embedding_model: str, update_model: bool = False, ): - if embedding_model and app.state.RAG_EMBEDDING_ENGINE == "": + if embedding_model and config_get(app.state.RAG_EMBEDDING_ENGINE) == "": app.state.sentence_transformer_ef = sentence_transformers.SentenceTransformer( get_model_path(embedding_model, update_model), device=DEVICE_TYPE, @@ -158,22 +160,22 @@ def update_reranking_model( update_embedding_model( - app.state.RAG_EMBEDDING_MODEL, + config_get(app.state.RAG_EMBEDDING_MODEL), RAG_EMBEDDING_MODEL_AUTO_UPDATE, ) update_reranking_model( - app.state.RAG_RERANKING_MODEL, + config_get(app.state.RAG_RERANKING_MODEL), RAG_RERANKING_MODEL_AUTO_UPDATE, ) app.state.EMBEDDING_FUNCTION = get_embedding_function( - app.state.RAG_EMBEDDING_ENGINE, - app.state.RAG_EMBEDDING_MODEL, + config_get(app.state.RAG_EMBEDDING_ENGINE), + config_get(app.state.RAG_EMBEDDING_MODEL), app.state.sentence_transformer_ef, - app.state.OPENAI_API_KEY, - app.state.OPENAI_API_BASE_URL, + config_get(app.state.OPENAI_API_KEY), + config_get(app.state.OPENAI_API_BASE_URL), ) origins = ["*"] @@ -200,12 +202,12 @@ class UrlForm(CollectionNameForm): async def get_status(): return { "status": True, - "chunk_size": app.state.CHUNK_SIZE, - "chunk_overlap": app.state.CHUNK_OVERLAP, - "template": app.state.RAG_TEMPLATE, - "embedding_engine": app.state.RAG_EMBEDDING_ENGINE, - "embedding_model": app.state.RAG_EMBEDDING_MODEL, - "reranking_model": app.state.RAG_RERANKING_MODEL, + "chunk_size": config_get(app.state.CHUNK_SIZE), + "chunk_overlap": config_get(app.state.CHUNK_OVERLAP), + "template": config_get(app.state.RAG_TEMPLATE), + "embedding_engine": config_get(app.state.RAG_EMBEDDING_ENGINE), + "embedding_model": config_get(app.state.RAG_EMBEDDING_MODEL), + "reranking_model": config_get(app.state.RAG_RERANKING_MODEL), } @@ -213,18 +215,21 @@ async def get_status(): async def get_embedding_config(user=Depends(get_admin_user)): return { "status": True, - "embedding_engine": app.state.RAG_EMBEDDING_ENGINE, - "embedding_model": app.state.RAG_EMBEDDING_MODEL, + "embedding_engine": config_get(app.state.RAG_EMBEDDING_ENGINE), + "embedding_model": config_get(app.state.RAG_EMBEDDING_MODEL), "openai_config": { - "url": app.state.OPENAI_API_BASE_URL, - "key": app.state.OPENAI_API_KEY, + "url": config_get(app.state.OPENAI_API_BASE_URL), + "key": config_get(app.state.OPENAI_API_KEY), }, } @app.get("/reranking") async def get_reraanking_config(user=Depends(get_admin_user)): - return {"status": True, "reranking_model": app.state.RAG_RERANKING_MODEL} + return { + "status": True, + "reranking_model": config_get(app.state.RAG_RERANKING_MODEL), + } class OpenAIConfigForm(BaseModel): @@ -246,31 +251,31 @@ async def update_embedding_config( f"Updating embedding model: {app.state.RAG_EMBEDDING_MODEL} to {form_data.embedding_model}" ) try: - app.state.RAG_EMBEDDING_ENGINE = form_data.embedding_engine - app.state.RAG_EMBEDDING_MODEL = form_data.embedding_model + config_set(app.state.RAG_EMBEDDING_ENGINE, form_data.embedding_engine) + config_set(app.state.RAG_EMBEDDING_MODEL, form_data.embedding_model) - if app.state.RAG_EMBEDDING_ENGINE in ["ollama", "openai"]: + if config_get(app.state.RAG_EMBEDDING_ENGINE) in ["ollama", "openai"]: if form_data.openai_config != None: - app.state.OPENAI_API_BASE_URL = form_data.openai_config.url - app.state.OPENAI_API_KEY = form_data.openai_config.key + config_set(app.state.OPENAI_API_BASE_URL, form_data.openai_config.url) + config_set(app.state.OPENAI_API_KEY, form_data.openai_config.key) - update_embedding_model(app.state.RAG_EMBEDDING_MODEL, True) + update_embedding_model(config_get(app.state.RAG_EMBEDDING_MODEL), True) app.state.EMBEDDING_FUNCTION = get_embedding_function( - app.state.RAG_EMBEDDING_ENGINE, - app.state.RAG_EMBEDDING_MODEL, + config_get(app.state.RAG_EMBEDDING_ENGINE), + config_get(app.state.RAG_EMBEDDING_MODEL), app.state.sentence_transformer_ef, - app.state.OPENAI_API_KEY, - app.state.OPENAI_API_BASE_URL, + config_get(app.state.OPENAI_API_KEY), + config_get(app.state.OPENAI_API_BASE_URL), ) return { "status": True, - "embedding_engine": app.state.RAG_EMBEDDING_ENGINE, - "embedding_model": app.state.RAG_EMBEDDING_MODEL, + "embedding_engine": config_get(app.state.RAG_EMBEDDING_ENGINE), + "embedding_model": config_get(app.state.RAG_EMBEDDING_MODEL), "openai_config": { - "url": app.state.OPENAI_API_BASE_URL, - "key": app.state.OPENAI_API_KEY, + "url": config_get(app.state.OPENAI_API_BASE_URL), + "key": config_get(app.state.OPENAI_API_KEY), }, } except Exception as e: @@ -293,13 +298,13 @@ async def update_reranking_config( f"Updating reranking model: {app.state.RAG_RERANKING_MODEL} to {form_data.reranking_model}" ) try: - app.state.RAG_RERANKING_MODEL = form_data.reranking_model + config_set(app.state.RAG_RERANKING_MODEL, form_data.reranking_model) - update_reranking_model(app.state.RAG_RERANKING_MODEL, True) + update_reranking_model(config_get(app.state.RAG_RERANKING_MODEL), True) return { "status": True, - "reranking_model": app.state.RAG_RERANKING_MODEL, + "reranking_model": config_get(app.state.RAG_RERANKING_MODEL), } except Exception as e: log.exception(f"Problem updating reranking model: {e}") @@ -313,14 +318,16 @@ async def update_reranking_config( async def get_rag_config(user=Depends(get_admin_user)): return { "status": True, - "pdf_extract_images": app.state.PDF_EXTRACT_IMAGES, + "pdf_extract_images": config_get(app.state.PDF_EXTRACT_IMAGES), "chunk": { - "chunk_size": app.state.CHUNK_SIZE, - "chunk_overlap": app.state.CHUNK_OVERLAP, + "chunk_size": config_get(app.state.CHUNK_SIZE), + "chunk_overlap": config_get(app.state.CHUNK_OVERLAP), }, - "web_loader_ssl_verification": app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION, + "web_loader_ssl_verification": config_get( + app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION + ), "youtube": { - "language": app.state.YOUTUBE_LOADER_LANGUAGE, + "language": config_get(app.state.YOUTUBE_LOADER_LANGUAGE), "translation": app.state.YOUTUBE_LOADER_TRANSLATION, }, } @@ -345,50 +352,69 @@ class ConfigUpdateForm(BaseModel): @app.post("/config/update") async def update_rag_config(form_data: ConfigUpdateForm, user=Depends(get_admin_user)): - app.state.PDF_EXTRACT_IMAGES = ( - form_data.pdf_extract_images - if form_data.pdf_extract_images != None - else app.state.PDF_EXTRACT_IMAGES + config_set( + app.state.PDF_EXTRACT_IMAGES, + ( + form_data.pdf_extract_images + if form_data.pdf_extract_images is not None + else config_get(app.state.PDF_EXTRACT_IMAGES) + ), ) - app.state.CHUNK_SIZE = ( - form_data.chunk.chunk_size if form_data.chunk != None else app.state.CHUNK_SIZE + config_set( + app.state.CHUNK_SIZE, + ( + form_data.chunk.chunk_size + if form_data.chunk is not None + else config_get(app.state.CHUNK_SIZE) + ), ) - app.state.CHUNK_OVERLAP = ( - form_data.chunk.chunk_overlap - if form_data.chunk != None - else app.state.CHUNK_OVERLAP + config_set( + app.state.CHUNK_OVERLAP, + ( + form_data.chunk.chunk_overlap + if form_data.chunk is not None + else config_get(app.state.CHUNK_OVERLAP) + ), ) - app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = ( - form_data.web_loader_ssl_verification - if form_data.web_loader_ssl_verification != None - else app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION + config_set( + app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION, + ( + form_data.web_loader_ssl_verification + if form_data.web_loader_ssl_verification != None + else config_get(app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION) + ), ) - app.state.YOUTUBE_LOADER_LANGUAGE = ( - form_data.youtube.language - if form_data.youtube != None - else app.state.YOUTUBE_LOADER_LANGUAGE + config_set( + app.state.YOUTUBE_LOADER_LANGUAGE, + ( + form_data.youtube.language + if form_data.youtube is not None + else config_get(app.state.YOUTUBE_LOADER_LANGUAGE) + ), ) app.state.YOUTUBE_LOADER_TRANSLATION = ( form_data.youtube.translation - if form_data.youtube != None + if form_data.youtube is not None else app.state.YOUTUBE_LOADER_TRANSLATION ) return { "status": True, - "pdf_extract_images": app.state.PDF_EXTRACT_IMAGES, + "pdf_extract_images": config_get(app.state.PDF_EXTRACT_IMAGES), "chunk": { - "chunk_size": app.state.CHUNK_SIZE, - "chunk_overlap": app.state.CHUNK_OVERLAP, + "chunk_size": config_get(app.state.CHUNK_SIZE), + "chunk_overlap": config_get(app.state.CHUNK_OVERLAP), }, - "web_loader_ssl_verification": app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION, + "web_loader_ssl_verification": config_get( + app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION + ), "youtube": { - "language": app.state.YOUTUBE_LOADER_LANGUAGE, + "language": config_get(app.state.YOUTUBE_LOADER_LANGUAGE), "translation": app.state.YOUTUBE_LOADER_TRANSLATION, }, } @@ -398,7 +424,7 @@ async def update_rag_config(form_data: ConfigUpdateForm, user=Depends(get_admin_ async def get_rag_template(user=Depends(get_current_user)): return { "status": True, - "template": app.state.RAG_TEMPLATE, + "template": config_get(app.state.RAG_TEMPLATE), } @@ -406,10 +432,10 @@ async def get_rag_template(user=Depends(get_current_user)): async def get_query_settings(user=Depends(get_admin_user)): return { "status": True, - "template": app.state.RAG_TEMPLATE, - "k": app.state.TOP_K, - "r": app.state.RELEVANCE_THRESHOLD, - "hybrid": app.state.ENABLE_RAG_HYBRID_SEARCH, + "template": config_get(app.state.RAG_TEMPLATE), + "k": config_get(app.state.TOP_K), + "r": config_get(app.state.RELEVANCE_THRESHOLD), + "hybrid": config_get(app.state.ENABLE_RAG_HYBRID_SEARCH), } @@ -424,16 +450,22 @@ class QuerySettingsForm(BaseModel): async def update_query_settings( form_data: QuerySettingsForm, user=Depends(get_admin_user) ): - app.state.RAG_TEMPLATE = form_data.template if form_data.template else RAG_TEMPLATE - app.state.TOP_K = form_data.k if form_data.k else 4 - app.state.RELEVANCE_THRESHOLD = form_data.r if form_data.r else 0.0 - app.state.ENABLE_RAG_HYBRID_SEARCH = form_data.hybrid if form_data.hybrid else False + config_set( + app.state.RAG_TEMPLATE, + form_data.template if form_data.template else RAG_TEMPLATE, + ) + config_set(app.state.TOP_K, form_data.k if form_data.k else 4) + config_set(app.state.RELEVANCE_THRESHOLD, form_data.r if form_data.r else 0.0) + config_set( + app.state.ENABLE_RAG_HYBRID_SEARCH, + form_data.hybrid if form_data.hybrid else False, + ) return { "status": True, - "template": app.state.RAG_TEMPLATE, - "k": app.state.TOP_K, - "r": app.state.RELEVANCE_THRESHOLD, - "hybrid": app.state.ENABLE_RAG_HYBRID_SEARCH, + "template": config_get(app.state.RAG_TEMPLATE), + "k": config_get(app.state.TOP_K), + "r": config_get(app.state.RELEVANCE_THRESHOLD), + "hybrid": config_get(app.state.ENABLE_RAG_HYBRID_SEARCH), } @@ -451,21 +483,25 @@ def query_doc_handler( user=Depends(get_current_user), ): try: - if app.state.ENABLE_RAG_HYBRID_SEARCH: + if config_get(app.state.ENABLE_RAG_HYBRID_SEARCH): return query_doc_with_hybrid_search( collection_name=form_data.collection_name, query=form_data.query, embedding_function=app.state.EMBEDDING_FUNCTION, - k=form_data.k if form_data.k else app.state.TOP_K, + k=form_data.k if form_data.k else config_get(app.state.TOP_K), reranking_function=app.state.sentence_transformer_rf, - r=form_data.r if form_data.r else app.state.RELEVANCE_THRESHOLD, + r=( + form_data.r + if form_data.r + else config_get(app.state.RELEVANCE_THRESHOLD) + ), ) else: return query_doc( collection_name=form_data.collection_name, query=form_data.query, embedding_function=app.state.EMBEDDING_FUNCTION, - k=form_data.k if form_data.k else app.state.TOP_K, + k=form_data.k if form_data.k else config_get(app.state.TOP_K), ) except Exception as e: log.exception(e) @@ -489,21 +525,25 @@ def query_collection_handler( user=Depends(get_current_user), ): try: - if app.state.ENABLE_RAG_HYBRID_SEARCH: + if config_get(app.state.ENABLE_RAG_HYBRID_SEARCH): return query_collection_with_hybrid_search( collection_names=form_data.collection_names, query=form_data.query, embedding_function=app.state.EMBEDDING_FUNCTION, - k=form_data.k if form_data.k else app.state.TOP_K, + k=form_data.k if form_data.k else config_get(app.state.TOP_K), reranking_function=app.state.sentence_transformer_rf, - r=form_data.r if form_data.r else app.state.RELEVANCE_THRESHOLD, + r=( + form_data.r + if form_data.r + else config_get(app.state.RELEVANCE_THRESHOLD) + ), ) else: return query_collection( collection_names=form_data.collection_names, query=form_data.query, embedding_function=app.state.EMBEDDING_FUNCTION, - k=form_data.k if form_data.k else app.state.TOP_K, + k=form_data.k if form_data.k else config_get(app.state.TOP_K), ) except Exception as e: @@ -520,8 +560,8 @@ def store_youtube_video(form_data: UrlForm, user=Depends(get_current_user)): loader = YoutubeLoader.from_youtube_url( form_data.url, add_video_info=True, - language=app.state.YOUTUBE_LOADER_LANGUAGE, - translation=app.state.YOUTUBE_LOADER_TRANSLATION, + language=config_get(app.state.YOUTUBE_LOADER_LANGUAGE), + translation=config_get(app.state.YOUTUBE_LOADER_TRANSLATION), ) data = loader.load() @@ -548,7 +588,8 @@ def store_web(form_data: UrlForm, user=Depends(get_current_user)): # "https://www.gutenberg.org/files/1727/1727-h/1727-h.htm" try: loader = get_web_loader( - form_data.url, verify_ssl=app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION + form_data.url, + verify_ssl=config_get(app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION), ) data = loader.load() @@ -604,8 +645,8 @@ def resolve_hostname(hostname): def store_data_in_vector_db(data, collection_name, overwrite: bool = False) -> bool: text_splitter = RecursiveCharacterTextSplitter( - chunk_size=app.state.CHUNK_SIZE, - chunk_overlap=app.state.CHUNK_OVERLAP, + chunk_size=config_get(app.state.CHUNK_SIZE), + chunk_overlap=config_get(app.state.CHUNK_OVERLAP), add_start_index=True, ) @@ -622,8 +663,8 @@ def store_text_in_vector_db( text, metadata, collection_name, overwrite: bool = False ) -> bool: text_splitter = RecursiveCharacterTextSplitter( - chunk_size=app.state.CHUNK_SIZE, - chunk_overlap=app.state.CHUNK_OVERLAP, + chunk_size=config_get(app.state.CHUNK_SIZE), + chunk_overlap=config_get(app.state.CHUNK_OVERLAP), add_start_index=True, ) docs = text_splitter.create_documents([text], metadatas=[metadata]) @@ -646,11 +687,11 @@ def store_docs_in_vector_db(docs, collection_name, overwrite: bool = False) -> b collection = CHROMA_CLIENT.create_collection(name=collection_name) embedding_func = get_embedding_function( - app.state.RAG_EMBEDDING_ENGINE, - app.state.RAG_EMBEDDING_MODEL, + config_get(app.state.RAG_EMBEDDING_ENGINE), + config_get(app.state.RAG_EMBEDDING_MODEL), app.state.sentence_transformer_ef, - app.state.OPENAI_API_KEY, - app.state.OPENAI_API_BASE_URL, + config_get(app.state.OPENAI_API_KEY), + config_get(app.state.OPENAI_API_BASE_URL), ) embedding_texts = list(map(lambda x: x.replace("\n", " "), texts)) @@ -724,7 +765,9 @@ def get_loader(filename: str, file_content_type: str, file_path: str): ] if file_ext == "pdf": - loader = PyPDFLoader(file_path, extract_images=app.state.PDF_EXTRACT_IMAGES) + loader = PyPDFLoader( + file_path, extract_images=config_get(app.state.PDF_EXTRACT_IMAGES) + ) elif file_ext == "csv": loader = CSVLoader(file_path) elif file_ext == "rst": diff --git a/backend/apps/web/main.py b/backend/apps/web/main.py index 66cdfb3d4..2bed33543 100644 --- a/backend/apps/web/main.py +++ b/backend/apps/web/main.py @@ -21,6 +21,8 @@ from config import ( USER_PERMISSIONS, WEBHOOK_URL, WEBUI_AUTH_TRUSTED_EMAIL_HEADER, + JWT_EXPIRES_IN, + config_get, ) app = FastAPI() @@ -28,7 +30,7 @@ app = FastAPI() origins = ["*"] app.state.ENABLE_SIGNUP = ENABLE_SIGNUP -app.state.JWT_EXPIRES_IN = "-1" +app.state.JWT_EXPIRES_IN = JWT_EXPIRES_IN app.state.DEFAULT_MODELS = DEFAULT_MODELS app.state.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS @@ -61,6 +63,6 @@ async def get_status(): return { "status": True, "auth": WEBUI_AUTH, - "default_models": app.state.DEFAULT_MODELS, - "default_prompt_suggestions": app.state.DEFAULT_PROMPT_SUGGESTIONS, + "default_models": config_get(app.state.DEFAULT_MODELS), + "default_prompt_suggestions": config_get(app.state.DEFAULT_PROMPT_SUGGESTIONS), } diff --git a/backend/apps/web/routers/auths.py b/backend/apps/web/routers/auths.py index 9fa962dda..0bc4967f9 100644 --- a/backend/apps/web/routers/auths.py +++ b/backend/apps/web/routers/auths.py @@ -33,7 +33,7 @@ from utils.utils import ( from utils.misc import parse_duration, validate_email_format from utils.webhook import post_webhook from constants import ERROR_MESSAGES, WEBHOOK_MESSAGES -from config import WEBUI_AUTH, WEBUI_AUTH_TRUSTED_EMAIL_HEADER +from config import WEBUI_AUTH, WEBUI_AUTH_TRUSTED_EMAIL_HEADER, config_get, config_set router = APIRouter() @@ -140,7 +140,7 @@ async def signin(request: Request, form_data: SigninForm): if user: token = create_token( data={"id": user.id}, - expires_delta=parse_duration(request.app.state.JWT_EXPIRES_IN), + expires_delta=parse_duration(config_get(request.app.state.JWT_EXPIRES_IN)), ) return { @@ -163,7 +163,7 @@ async def signin(request: Request, form_data: SigninForm): @router.post("/signup", response_model=SigninResponse) async def signup(request: Request, form_data: SignupForm): - if not request.app.state.ENABLE_SIGNUP and WEBUI_AUTH: + if not config_get(request.app.state.ENABLE_SIGNUP) and WEBUI_AUTH: raise HTTPException( status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED ) @@ -180,7 +180,7 @@ async def signup(request: Request, form_data: SignupForm): role = ( "admin" if Users.get_num_users() == 0 - else request.app.state.DEFAULT_USER_ROLE + else config_get(request.app.state.DEFAULT_USER_ROLE) ) hashed = get_password_hash(form_data.password) user = Auths.insert_new_auth( @@ -194,13 +194,15 @@ async def signup(request: Request, form_data: SignupForm): if user: token = create_token( data={"id": user.id}, - expires_delta=parse_duration(request.app.state.JWT_EXPIRES_IN), + expires_delta=parse_duration( + config_get(request.app.state.JWT_EXPIRES_IN) + ), ) # response.set_cookie(key='token', value=token, httponly=True) - if request.app.state.WEBHOOK_URL: + if config_get(request.app.state.WEBHOOK_URL): post_webhook( - request.app.state.WEBHOOK_URL, + config_get(request.app.state.WEBHOOK_URL), WEBHOOK_MESSAGES.USER_SIGNUP(user.name), { "action": "signup", @@ -276,13 +278,15 @@ async def add_user(form_data: AddUserForm, user=Depends(get_admin_user)): @router.get("/signup/enabled", response_model=bool) async def get_sign_up_status(request: Request, user=Depends(get_admin_user)): - return request.app.state.ENABLE_SIGNUP + return config_get(request.app.state.ENABLE_SIGNUP) @router.get("/signup/enabled/toggle", response_model=bool) async def toggle_sign_up(request: Request, user=Depends(get_admin_user)): - request.app.state.ENABLE_SIGNUP = not request.app.state.ENABLE_SIGNUP - return request.app.state.ENABLE_SIGNUP + config_set( + request.app.state.ENABLE_SIGNUP, not config_get(request.app.state.ENABLE_SIGNUP) + ) + return config_get(request.app.state.ENABLE_SIGNUP) ############################ @@ -292,7 +296,7 @@ async def toggle_sign_up(request: Request, user=Depends(get_admin_user)): @router.get("/signup/user/role") async def get_default_user_role(request: Request, user=Depends(get_admin_user)): - return request.app.state.DEFAULT_USER_ROLE + return config_get(request.app.state.DEFAULT_USER_ROLE) class UpdateRoleForm(BaseModel): @@ -304,8 +308,8 @@ async def update_default_user_role( request: Request, form_data: UpdateRoleForm, user=Depends(get_admin_user) ): if form_data.role in ["pending", "user", "admin"]: - request.app.state.DEFAULT_USER_ROLE = form_data.role - return request.app.state.DEFAULT_USER_ROLE + config_set(request.app.state.DEFAULT_USER_ROLE, form_data.role) + return config_get(request.app.state.DEFAULT_USER_ROLE) ############################ @@ -315,7 +319,7 @@ async def update_default_user_role( @router.get("/token/expires") async def get_token_expires_duration(request: Request, user=Depends(get_admin_user)): - return request.app.state.JWT_EXPIRES_IN + return config_get(request.app.state.JWT_EXPIRES_IN) class UpdateJWTExpiresDurationForm(BaseModel): @@ -332,10 +336,10 @@ async def update_token_expires_duration( # Check if the input string matches the pattern if re.match(pattern, form_data.duration): - request.app.state.JWT_EXPIRES_IN = form_data.duration - return request.app.state.JWT_EXPIRES_IN + config_set(request.app.state.JWT_EXPIRES_IN, form_data.duration) + return config_get(request.app.state.JWT_EXPIRES_IN) else: - return request.app.state.JWT_EXPIRES_IN + return config_get(request.app.state.JWT_EXPIRES_IN) ############################ diff --git a/backend/apps/web/routers/configs.py b/backend/apps/web/routers/configs.py index 0bad55a6a..d726cd2dc 100644 --- a/backend/apps/web/routers/configs.py +++ b/backend/apps/web/routers/configs.py @@ -9,6 +9,7 @@ import time import uuid from apps.web.models.users import Users +from config import config_set, config_get from utils.utils import ( get_password_hash, @@ -44,8 +45,8 @@ class SetDefaultSuggestionsForm(BaseModel): async def set_global_default_models( request: Request, form_data: SetDefaultModelsForm, user=Depends(get_admin_user) ): - request.app.state.DEFAULT_MODELS = form_data.models - return request.app.state.DEFAULT_MODELS + config_set(request.app.state.DEFAULT_MODELS, form_data.models) + return config_get(request.app.state.DEFAULT_MODELS) @router.post("/default/suggestions", response_model=List[PromptSuggestion]) @@ -55,5 +56,5 @@ async def set_global_default_suggestions( user=Depends(get_admin_user), ): data = form_data.model_dump() - request.app.state.DEFAULT_PROMPT_SUGGESTIONS = data["suggestions"] - return request.app.state.DEFAULT_PROMPT_SUGGESTIONS + config_set(request.app.state.DEFAULT_PROMPT_SUGGESTIONS, data["suggestions"]) + return config_get(request.app.state.DEFAULT_PROMPT_SUGGESTIONS) diff --git a/backend/apps/web/routers/users.py b/backend/apps/web/routers/users.py index 59f6c21b7..302432540 100644 --- a/backend/apps/web/routers/users.py +++ b/backend/apps/web/routers/users.py @@ -15,7 +15,7 @@ from apps.web.models.auths import Auths from utils.utils import get_current_user, get_password_hash, get_admin_user from constants import ERROR_MESSAGES -from config import SRC_LOG_LEVELS +from config import SRC_LOG_LEVELS, config_set, config_get log = logging.getLogger(__name__) log.setLevel(SRC_LOG_LEVELS["MODELS"]) @@ -39,15 +39,15 @@ async def get_users(skip: int = 0, limit: int = 50, user=Depends(get_admin_user) @router.get("/permissions/user") async def get_user_permissions(request: Request, user=Depends(get_admin_user)): - return request.app.state.USER_PERMISSIONS + return config_get(request.app.state.USER_PERMISSIONS) @router.post("/permissions/user") async def update_user_permissions( request: Request, form_data: dict, user=Depends(get_admin_user) ): - request.app.state.USER_PERMISSIONS = form_data - return request.app.state.USER_PERMISSIONS + config_set(request.app.state.USER_PERMISSIONS, form_data) + return config_get(request.app.state.USER_PERMISSIONS) ############################ diff --git a/backend/config.py b/backend/config.py index 5c6247a9f..028e6caf0 100644 --- a/backend/config.py +++ b/backend/config.py @@ -5,6 +5,7 @@ import chromadb from chromadb import Settings from base64 import b64encode from bs4 import BeautifulSoup +from typing import TypeVar, Generic, Union from pathlib import Path import json @@ -17,7 +18,6 @@ import shutil from secrets import token_bytes from constants import ERROR_MESSAGES - #################################### # Load .env file #################################### @@ -29,7 +29,6 @@ try: except ImportError: print("dotenv not installed, skipping...") - #################################### # LOGGING #################################### @@ -71,7 +70,6 @@ for source in log_sources: log.setLevel(SRC_LOG_LEVELS["CONFIG"]) - WEBUI_NAME = os.environ.get("WEBUI_NAME", "Open WebUI") if WEBUI_NAME != "Open WebUI": WEBUI_NAME += " (Open WebUI)" @@ -80,7 +78,6 @@ WEBUI_URL = os.environ.get("WEBUI_URL", "http://localhost:3000") WEBUI_FAVICON_URL = "https://openwebui.com/favicon.png" - #################################### # ENV (dev,test,prod) #################################### @@ -151,26 +148,14 @@ for version in soup.find_all("h2"): changelog_json[version_number] = version_data - CHANGELOG = changelog_json - #################################### # WEBUI_VERSION #################################### WEBUI_VERSION = os.environ.get("WEBUI_VERSION", "v1.0.0-alpha.100") -#################################### -# WEBUI_AUTH (Required for security) -#################################### - -WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true" -WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get( - "WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None -) - - #################################### # DATA/FRONTEND BUILD DIR #################################### @@ -184,6 +169,93 @@ try: except: CONFIG_DATA = {} + +#################################### +# Config helpers +#################################### + + +def save_config(): + try: + with open(f"{DATA_DIR}/config.json", "w") as f: + json.dump(CONFIG_DATA, f, indent="\t") + except Exception as e: + log.exception(e) + + +def get_config_value(config_path: str): + path_parts = config_path.split(".") + cur_config = CONFIG_DATA + for key in path_parts: + if key in cur_config: + cur_config = cur_config[key] + else: + return None + return cur_config + + +T = TypeVar("T") + + +class WrappedConfig(Generic[T]): + def __init__(self, env_name: str, config_path: str, env_value: T): + self.env_name = env_name + self.config_path = config_path + self.env_value = env_value + self.config_value = get_config_value(config_path) + if self.config_value is not None: + log.info(f"'{env_name}' loaded from config.json") + self.value = self.config_value + else: + self.value = env_value + + def __str__(self): + return str(self.value) + + def save(self): + # Don't save if the value is the same as the env value and the config value + if self.env_value == self.value: + if self.config_value == self.value: + return + log.info(f"Saving '{self.env_name}' to config.json") + path_parts = self.config_path.split(".") + config = CONFIG_DATA + for key in path_parts[:-1]: + if key not in config: + config[key] = {} + config = config[key] + config[path_parts[-1]] = self.value + save_config() + self.config_value = self.value + + +def config_set(config: Union[WrappedConfig[T], T], value: T, save_config=True): + if isinstance(config, WrappedConfig): + config.value = value + if save_config: + config.save() + else: + config = value + + +def config_get(config: Union[WrappedConfig[T], T]) -> T: + if isinstance(config, WrappedConfig): + return config.value + return config + + +#################################### +# WEBUI_AUTH (Required for security) +#################################### + +WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true" +WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get( + "WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None +) +JWT_EXPIRES_IN = WrappedConfig( + "JWT_EXPIRES_IN", "auth.jwt_expiry", os.environ.get("JWT_EXPIRES_IN", "-1") +) + #################################### # Static DIR #################################### @@ -225,7 +297,6 @@ if CUSTOM_NAME: log.exception(e) pass - #################################### # File Upload DIR #################################### @@ -233,7 +304,6 @@ if CUSTOM_NAME: UPLOAD_DIR = f"{DATA_DIR}/uploads" Path(UPLOAD_DIR).mkdir(parents=True, exist_ok=True) - #################################### # Cache DIR #################################### @@ -241,7 +311,6 @@ Path(UPLOAD_DIR).mkdir(parents=True, exist_ok=True) CACHE_DIR = f"{DATA_DIR}/cache" Path(CACHE_DIR).mkdir(parents=True, exist_ok=True) - #################################### # Docs DIR #################################### @@ -282,7 +351,6 @@ if not os.path.exists(LITELLM_CONFIG_PATH): create_config_file(LITELLM_CONFIG_PATH) log.info("Config file created successfully.") - #################################### # OLLAMA_BASE_URL #################################### @@ -313,12 +381,13 @@ if ENV == "prod": elif K8S_FLAG: OLLAMA_BASE_URL = "http://ollama-service.open-webui.svc.cluster.local:11434" - OLLAMA_BASE_URLS = os.environ.get("OLLAMA_BASE_URLS", "") OLLAMA_BASE_URLS = OLLAMA_BASE_URLS if OLLAMA_BASE_URLS != "" else OLLAMA_BASE_URL OLLAMA_BASE_URLS = [url.strip() for url in OLLAMA_BASE_URLS.split(";")] - +OLLAMA_BASE_URLS = WrappedConfig( + "OLLAMA_BASE_URLS", "ollama.base_urls", OLLAMA_BASE_URLS +) #################################### # OPENAI_API @@ -327,7 +396,6 @@ OLLAMA_BASE_URLS = [url.strip() for url in OLLAMA_BASE_URLS.split(";")] OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "") OPENAI_API_BASE_URL = os.environ.get("OPENAI_API_BASE_URL", "") - if OPENAI_API_BASE_URL == "": OPENAI_API_BASE_URL = "https://api.openai.com/v1" @@ -335,7 +403,7 @@ OPENAI_API_KEYS = os.environ.get("OPENAI_API_KEYS", "") OPENAI_API_KEYS = OPENAI_API_KEYS if OPENAI_API_KEYS != "" else OPENAI_API_KEY OPENAI_API_KEYS = [url.strip() for url in OPENAI_API_KEYS.split(";")] - +OPENAI_API_KEYS = WrappedConfig("OPENAI_API_KEYS", "openai.api_keys", OPENAI_API_KEYS) OPENAI_API_BASE_URLS = os.environ.get("OPENAI_API_BASE_URLS", "") OPENAI_API_BASE_URLS = ( @@ -346,37 +414,42 @@ OPENAI_API_BASE_URLS = [ url.strip() if url != "" else "https://api.openai.com/v1" for url in OPENAI_API_BASE_URLS.split(";") ] +OPENAI_API_BASE_URLS = WrappedConfig( + "OPENAI_API_BASE_URLS", "openai.api_base_urls", OPENAI_API_BASE_URLS +) OPENAI_API_KEY = "" try: - OPENAI_API_KEY = OPENAI_API_KEYS[ - OPENAI_API_BASE_URLS.index("https://api.openai.com/v1") + OPENAI_API_KEY = OPENAI_API_KEYS.value[ + OPENAI_API_BASE_URLS.value.index("https://api.openai.com/v1") ] except: pass OPENAI_API_BASE_URL = "https://api.openai.com/v1" - #################################### # WEBUI #################################### -ENABLE_SIGNUP = ( - False - if WEBUI_AUTH == False - else os.environ.get("ENABLE_SIGNUP", "True").lower() == "true" +ENABLE_SIGNUP = WrappedConfig( + "ENABLE_SIGNUP", + "ui.enable_signup", + ( + False + if not WEBUI_AUTH + else os.environ.get("ENABLE_SIGNUP", "True").lower() == "true" + ), +) +DEFAULT_MODELS = WrappedConfig( + "DEFAULT_MODELS", "ui.default_models", os.environ.get("DEFAULT_MODELS", None) ) -DEFAULT_MODELS = os.environ.get("DEFAULT_MODELS", None) - -DEFAULT_PROMPT_SUGGESTIONS = ( - CONFIG_DATA["ui"]["prompt_suggestions"] - if "ui" in CONFIG_DATA - and "prompt_suggestions" in CONFIG_DATA["ui"] - and type(CONFIG_DATA["ui"]["prompt_suggestions"]) is list - else [ +DEFAULT_PROMPT_SUGGESTIONS = WrappedConfig( + "DEFAULT_PROMPT_SUGGESTIONS", + "ui.prompt_suggestions", + [ { "title": ["Help me study", "vocabulary for a college entrance exam"], "content": "Help me study vocabulary: write a sentence for me to fill in the blank, and I'll try to pick the correct option.", @@ -404,23 +477,42 @@ DEFAULT_PROMPT_SUGGESTIONS = ( "title": ["Overcome procrastination", "give me tips"], "content": "Could you start by asking me about instances when I procrastinate the most and then give me some suggestions to overcome it?", }, - ] + ], ) - -DEFAULT_USER_ROLE = os.getenv("DEFAULT_USER_ROLE", "pending") - -USER_PERMISSIONS_CHAT_DELETION = ( - os.environ.get("USER_PERMISSIONS_CHAT_DELETION", "True").lower() == "true" +DEFAULT_USER_ROLE = WrappedConfig( + "DEFAULT_USER_ROLE", + "ui.default_user_role", + os.getenv("DEFAULT_USER_ROLE", "pending"), ) -USER_PERMISSIONS = {"chat": {"deletion": USER_PERMISSIONS_CHAT_DELETION}} +USER_PERMISSIONS_CHAT_DELETION = WrappedConfig( + "USER_PERMISSIONS_CHAT_DELETION", + "ui.user_permissions.chat.deletion", + os.environ.get("USER_PERMISSIONS_CHAT_DELETION", "True").lower() == "true", +) -ENABLE_MODEL_FILTER = os.environ.get("ENABLE_MODEL_FILTER", "False").lower() == "true" +USER_PERMISSIONS = WrappedConfig( + "USER_PERMISSIONS", + "ui.user_permissions", + {"chat": {"deletion": USER_PERMISSIONS_CHAT_DELETION}}, +) + +ENABLE_MODEL_FILTER = WrappedConfig( + "ENABLE_MODEL_FILTER", + "model_filter.enable", + os.environ.get("ENABLE_MODEL_FILTER", "False").lower() == "true", +) MODEL_FILTER_LIST = os.environ.get("MODEL_FILTER_LIST", "") -MODEL_FILTER_LIST = [model.strip() for model in MODEL_FILTER_LIST.split(";")] +MODEL_FILTER_LIST = WrappedConfig( + "MODEL_FILTER_LIST", + "model_filter.list", + [model.strip() for model in MODEL_FILTER_LIST.split(";")], +) -WEBHOOK_URL = os.environ.get("WEBHOOK_URL", "") +WEBHOOK_URL = WrappedConfig( + "WEBHOOK_URL", "webhook_url", os.environ.get("WEBHOOK_URL", "") +) ENABLE_ADMIN_EXPORT = os.environ.get("ENABLE_ADMIN_EXPORT", "True").lower() == "true" @@ -458,26 +550,45 @@ else: CHROMA_HTTP_SSL = os.environ.get("CHROMA_HTTP_SSL", "false").lower() == "true" # this uses the model defined in the Dockerfile ENV variable. If you dont use docker or docker based deployments such as k8s, the default embedding model will be used (sentence-transformers/all-MiniLM-L6-v2) -RAG_TOP_K = int(os.environ.get("RAG_TOP_K", "5")) -RAG_RELEVANCE_THRESHOLD = float(os.environ.get("RAG_RELEVANCE_THRESHOLD", "0.0")) - -ENABLE_RAG_HYBRID_SEARCH = ( - os.environ.get("ENABLE_RAG_HYBRID_SEARCH", "").lower() == "true" +RAG_TOP_K = WrappedConfig( + "RAG_TOP_K", "rag.top_k", int(os.environ.get("RAG_TOP_K", "5")) +) +RAG_RELEVANCE_THRESHOLD = WrappedConfig( + "RAG_RELEVANCE_THRESHOLD", + "rag.relevance_threshold", + float(os.environ.get("RAG_RELEVANCE_THRESHOLD", "0.0")), ) - -ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = ( - os.environ.get("ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION", "True").lower() == "true" +ENABLE_RAG_HYBRID_SEARCH = WrappedConfig( + "ENABLE_RAG_HYBRID_SEARCH", + "rag.enable_hybrid_search", + os.environ.get("ENABLE_RAG_HYBRID_SEARCH", "").lower() == "true", ) -RAG_EMBEDDING_ENGINE = os.environ.get("RAG_EMBEDDING_ENGINE", "") - -PDF_EXTRACT_IMAGES = os.environ.get("PDF_EXTRACT_IMAGES", "False").lower() == "true" - -RAG_EMBEDDING_MODEL = os.environ.get( - "RAG_EMBEDDING_MODEL", "sentence-transformers/all-MiniLM-L6-v2" +ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = WrappedConfig( + "ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION", + "rag.enable_web_loader_ssl_verification", + os.environ.get("ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION", "True").lower() == "true", ) -log.info(f"Embedding model set: {RAG_EMBEDDING_MODEL}"), + +RAG_EMBEDDING_ENGINE = WrappedConfig( + "RAG_EMBEDDING_ENGINE", + "rag.embedding_engine", + os.environ.get("RAG_EMBEDDING_ENGINE", ""), +) + +PDF_EXTRACT_IMAGES = WrappedConfig( + "PDF_EXTRACT_IMAGES", + "rag.pdf_extract_images", + os.environ.get("PDF_EXTRACT_IMAGES", "False").lower() == "true", +) + +RAG_EMBEDDING_MODEL = WrappedConfig( + "RAG_EMBEDDING_MODEL", + "rag.embedding_model", + os.environ.get("RAG_EMBEDDING_MODEL", "sentence-transformers/all-MiniLM-L6-v2"), +) +log.info(f"Embedding model set: {RAG_EMBEDDING_MODEL.value}"), RAG_EMBEDDING_MODEL_AUTO_UPDATE = ( os.environ.get("RAG_EMBEDDING_MODEL_AUTO_UPDATE", "").lower() == "true" @@ -487,9 +598,13 @@ RAG_EMBEDDING_MODEL_TRUST_REMOTE_CODE = ( os.environ.get("RAG_EMBEDDING_MODEL_TRUST_REMOTE_CODE", "").lower() == "true" ) -RAG_RERANKING_MODEL = os.environ.get("RAG_RERANKING_MODEL", "") -if not RAG_RERANKING_MODEL == "": - log.info(f"Reranking model set: {RAG_RERANKING_MODEL}"), +RAG_RERANKING_MODEL = WrappedConfig( + "RAG_RERANKING_MODEL", + "rag.reranking_model", + os.environ.get("RAG_RERANKING_MODEL", ""), +) +if RAG_RERANKING_MODEL.value != "": + log.info(f"Reranking model set: {RAG_RERANKING_MODEL.value}"), RAG_RERANKING_MODEL_AUTO_UPDATE = ( os.environ.get("RAG_RERANKING_MODEL_AUTO_UPDATE", "").lower() == "true" @@ -499,7 +614,6 @@ RAG_RERANKING_MODEL_TRUST_REMOTE_CODE = ( os.environ.get("RAG_RERANKING_MODEL_TRUST_REMOTE_CODE", "").lower() == "true" ) - if CHROMA_HTTP_HOST != "": CHROMA_CLIENT = chromadb.HttpClient( host=CHROMA_HTTP_HOST, @@ -518,7 +632,6 @@ else: database=CHROMA_DATABASE, ) - # device type embedding models - "cpu" (default), "cuda" (nvidia gpu required) or "mps" (apple silicon) - choosing this right can lead to better performance USE_CUDA = os.environ.get("USE_CUDA_DOCKER", "false") @@ -527,9 +640,14 @@ if USE_CUDA.lower() == "true": else: DEVICE_TYPE = "cpu" - -CHUNK_SIZE = int(os.environ.get("CHUNK_SIZE", "1500")) -CHUNK_OVERLAP = int(os.environ.get("CHUNK_OVERLAP", "100")) +CHUNK_SIZE = WrappedConfig( + "CHUNK_SIZE", "rag.chunk_size", int(os.environ.get("CHUNK_SIZE", "1500")) +) +CHUNK_OVERLAP = WrappedConfig( + "CHUNK_OVERLAP", + "rag.chunk_overlap", + int(os.environ.get("CHUNK_OVERLAP", "100")), +) DEFAULT_RAG_TEMPLATE = """Use the following context as your learned knowledge, inside XML tags. @@ -545,16 +663,32 @@ And answer according to the language of the user's question. Given the context information, answer the query. Query: [query]""" -RAG_TEMPLATE = os.environ.get("RAG_TEMPLATE", DEFAULT_RAG_TEMPLATE) +RAG_TEMPLATE = WrappedConfig( + "RAG_TEMPLATE", + "rag.template", + os.environ.get("RAG_TEMPLATE", DEFAULT_RAG_TEMPLATE), +) -RAG_OPENAI_API_BASE_URL = os.getenv("RAG_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL) -RAG_OPENAI_API_KEY = os.getenv("RAG_OPENAI_API_KEY", OPENAI_API_KEY) +RAG_OPENAI_API_BASE_URL = WrappedConfig( + "RAG_OPENAI_API_BASE_URL", + "rag.openai_api_base_url", + os.getenv("RAG_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL), +) +RAG_OPENAI_API_KEY = WrappedConfig( + "RAG_OPENAI_API_KEY", + "rag.openai_api_key", + os.getenv("RAG_OPENAI_API_KEY", OPENAI_API_KEY), +) ENABLE_RAG_LOCAL_WEB_FETCH = ( os.getenv("ENABLE_RAG_LOCAL_WEB_FETCH", "False").lower() == "true" ) -YOUTUBE_LOADER_LANGUAGE = os.getenv("YOUTUBE_LOADER_LANGUAGE", "en").split(",") +YOUTUBE_LOADER_LANGUAGE = WrappedConfig( + "YOUTUBE_LOADER_LANGUAGE", + "rag.youtube_loader_language", + os.getenv("YOUTUBE_LOADER_LANGUAGE", "en").split(","), +) #################################### # Transcribe @@ -566,39 +700,82 @@ WHISPER_MODEL_AUTO_UPDATE = ( os.environ.get("WHISPER_MODEL_AUTO_UPDATE", "").lower() == "true" ) - #################################### # Images #################################### -IMAGE_GENERATION_ENGINE = os.getenv("IMAGE_GENERATION_ENGINE", "") - -ENABLE_IMAGE_GENERATION = ( - os.environ.get("ENABLE_IMAGE_GENERATION", "").lower() == "true" +IMAGE_GENERATION_ENGINE = WrappedConfig( + "IMAGE_GENERATION_ENGINE", + "image_generation.engine", + os.getenv("IMAGE_GENERATION_ENGINE", ""), ) -AUTOMATIC1111_BASE_URL = os.getenv("AUTOMATIC1111_BASE_URL", "") -COMFYUI_BASE_URL = os.getenv("COMFYUI_BASE_URL", "") - -IMAGES_OPENAI_API_BASE_URL = os.getenv( - "IMAGES_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL +ENABLE_IMAGE_GENERATION = WrappedConfig( + "ENABLE_IMAGE_GENERATION", + "image_generation.enable", + os.environ.get("ENABLE_IMAGE_GENERATION", "").lower() == "true", +) +AUTOMATIC1111_BASE_URL = WrappedConfig( + "AUTOMATIC1111_BASE_URL", + "image_generation.automatic1111.base_url", + os.getenv("AUTOMATIC1111_BASE_URL", ""), ) -IMAGES_OPENAI_API_KEY = os.getenv("IMAGES_OPENAI_API_KEY", OPENAI_API_KEY) -IMAGE_SIZE = os.getenv("IMAGE_SIZE", "512x512") +COMFYUI_BASE_URL = WrappedConfig( + "COMFYUI_BASE_URL", + "image_generation.comfyui.base_url", + os.getenv("COMFYUI_BASE_URL", ""), +) -IMAGE_STEPS = int(os.getenv("IMAGE_STEPS", 50)) +IMAGES_OPENAI_API_BASE_URL = WrappedConfig( + "IMAGES_OPENAI_API_BASE_URL", + "image_generation.openai.api_base_url", + os.getenv("IMAGES_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL), +) +IMAGES_OPENAI_API_KEY = WrappedConfig( + "IMAGES_OPENAI_API_KEY", + "image_generation.openai.api_key", + os.getenv("IMAGES_OPENAI_API_KEY", OPENAI_API_KEY), +) -IMAGE_GENERATION_MODEL = os.getenv("IMAGE_GENERATION_MODEL", "") +IMAGE_SIZE = WrappedConfig( + "IMAGE_SIZE", "image_generation.size", os.getenv("IMAGE_SIZE", "512x512") +) + +IMAGE_STEPS = WrappedConfig( + "IMAGE_STEPS", "image_generation.steps", int(os.getenv("IMAGE_STEPS", 50)) +) + +IMAGE_GENERATION_MODEL = WrappedConfig( + "IMAGE_GENERATION_MODEL", + "image_generation.model", + os.getenv("IMAGE_GENERATION_MODEL", ""), +) #################################### # Audio #################################### -AUDIO_OPENAI_API_BASE_URL = os.getenv("AUDIO_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL) -AUDIO_OPENAI_API_KEY = os.getenv("AUDIO_OPENAI_API_KEY", OPENAI_API_KEY) -AUDIO_OPENAI_API_MODEL = os.getenv("AUDIO_OPENAI_API_MODEL", "tts-1") -AUDIO_OPENAI_API_VOICE = os.getenv("AUDIO_OPENAI_API_VOICE", "alloy") +AUDIO_OPENAI_API_BASE_URL = WrappedConfig( + "AUDIO_OPENAI_API_BASE_URL", + "audio.openai.api_base_url", + os.getenv("AUDIO_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL), +) +AUDIO_OPENAI_API_KEY = WrappedConfig( + "AUDIO_OPENAI_API_KEY", + "audio.openai.api_key", + os.getenv("AUDIO_OPENAI_API_KEY", OPENAI_API_KEY), +) +AUDIO_OPENAI_API_MODEL = WrappedConfig( + "AUDIO_OPENAI_API_MODEL", + "audio.openai.api_model", + os.getenv("AUDIO_OPENAI_API_MODEL", "tts-1"), +) +AUDIO_OPENAI_API_VOICE = WrappedConfig( + "AUDIO_OPENAI_API_VOICE", + "audio.openai.api_voice", + os.getenv("AUDIO_OPENAI_API_VOICE", "alloy"), +) #################################### # LiteLLM @@ -612,7 +789,6 @@ if LITELLM_PROXY_PORT < 0 or LITELLM_PROXY_PORT > 65535: raise ValueError("Invalid port number for LITELLM_PROXY_PORT") LITELLM_PROXY_HOST = os.getenv("LITELLM_PROXY_HOST", "127.0.0.1") - #################################### # Database #################################### diff --git a/backend/main.py b/backend/main.py index 139819f7c..6f94a8dad 100644 --- a/backend/main.py +++ b/backend/main.py @@ -58,6 +58,8 @@ from config import ( SRC_LOG_LEVELS, WEBHOOK_URL, ENABLE_ADMIN_EXPORT, + config_get, + config_set, ) from constants import ERROR_MESSAGES @@ -243,9 +245,11 @@ async def get_app_config(): "version": VERSION, "auth": WEBUI_AUTH, "default_locale": default_locale, - "images": images_app.state.ENABLED, - "default_models": webui_app.state.DEFAULT_MODELS, - "default_prompt_suggestions": webui_app.state.DEFAULT_PROMPT_SUGGESTIONS, + "images": config_get(images_app.state.ENABLED), + "default_models": config_get(webui_app.state.DEFAULT_MODELS), + "default_prompt_suggestions": config_get( + webui_app.state.DEFAULT_PROMPT_SUGGESTIONS + ), "trusted_header_auth": bool(webui_app.state.AUTH_TRUSTED_EMAIL_HEADER), "admin_export_enabled": ENABLE_ADMIN_EXPORT, } @@ -254,8 +258,8 @@ async def get_app_config(): @app.get("/api/config/model/filter") async def get_model_filter_config(user=Depends(get_admin_user)): return { - "enabled": app.state.ENABLE_MODEL_FILTER, - "models": app.state.MODEL_FILTER_LIST, + "enabled": config_get(app.state.ENABLE_MODEL_FILTER), + "models": config_get(app.state.MODEL_FILTER_LIST), } @@ -268,28 +272,28 @@ class ModelFilterConfigForm(BaseModel): async def update_model_filter_config( form_data: ModelFilterConfigForm, user=Depends(get_admin_user) ): - app.state.ENABLE_MODEL_FILTER = form_data.enabled - app.state.MODEL_FILTER_LIST = form_data.models + config_set(app.state.ENABLE_MODEL_FILTER, form_data.enabled) + config_set(app.state.MODEL_FILTER_LIST, form_data.models) - ollama_app.state.ENABLE_MODEL_FILTER = app.state.ENABLE_MODEL_FILTER - ollama_app.state.MODEL_FILTER_LIST = app.state.MODEL_FILTER_LIST + ollama_app.state.ENABLE_MODEL_FILTER = config_get(app.state.ENABLE_MODEL_FILTER) + ollama_app.state.MODEL_FILTER_LIST = config_get(app.state.MODEL_FILTER_LIST) - openai_app.state.ENABLE_MODEL_FILTER = app.state.ENABLE_MODEL_FILTER - openai_app.state.MODEL_FILTER_LIST = app.state.MODEL_FILTER_LIST + openai_app.state.ENABLE_MODEL_FILTER = config_get(app.state.ENABLE_MODEL_FILTER) + openai_app.state.MODEL_FILTER_LIST = config_get(app.state.MODEL_FILTER_LIST) - litellm_app.state.ENABLE_MODEL_FILTER = app.state.ENABLE_MODEL_FILTER - litellm_app.state.MODEL_FILTER_LIST = app.state.MODEL_FILTER_LIST + litellm_app.state.ENABLE_MODEL_FILTER = config_get(app.state.ENABLE_MODEL_FILTER) + litellm_app.state.MODEL_FILTER_LIST = config_get(app.state.MODEL_FILTER_LIST) return { - "enabled": app.state.ENABLE_MODEL_FILTER, - "models": app.state.MODEL_FILTER_LIST, + "enabled": config_get(app.state.ENABLE_MODEL_FILTER), + "models": config_get(app.state.MODEL_FILTER_LIST), } @app.get("/api/webhook") async def get_webhook_url(user=Depends(get_admin_user)): return { - "url": app.state.WEBHOOK_URL, + "url": config_get(app.state.WEBHOOK_URL), } @@ -299,12 +303,12 @@ class UrlForm(BaseModel): @app.post("/api/webhook") async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)): - app.state.WEBHOOK_URL = form_data.url + config_set(app.state.WEBHOOK_URL, form_data.url) - webui_app.state.WEBHOOK_URL = app.state.WEBHOOK_URL + webui_app.state.WEBHOOK_URL = config_get(app.state.WEBHOOK_URL) return { - "url": app.state.WEBHOOK_URL, + "url": config_get(app.state.WEBHOOK_URL), } From f712c900193d90b249f80efc15b22494dd467a30 Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Fri, 10 May 2024 14:18:39 +0800 Subject: [PATCH 06/29] feat: raise an exception if a WrappedConfig is used as a response --- backend/config.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/backend/config.py b/backend/config.py index 028e6caf0..9e7a9ef90 100644 --- a/backend/config.py +++ b/backend/config.py @@ -29,6 +29,7 @@ try: except ImportError: print("dotenv not installed, skipping...") + #################################### # LOGGING #################################### @@ -78,6 +79,7 @@ WEBUI_URL = os.environ.get("WEBUI_URL", "http://localhost:3000") WEBUI_FAVICON_URL = "https://openwebui.com/favicon.png" + #################################### # ENV (dev,test,prod) #################################### @@ -148,8 +150,10 @@ for version in soup.find_all("h2"): changelog_json[version_number] = version_data + CHANGELOG = changelog_json + #################################### # WEBUI_VERSION #################################### @@ -212,6 +216,19 @@ class WrappedConfig(Generic[T]): def __str__(self): return str(self.value) + @property + def __dict__(self): + raise TypeError( + "WrappedConfig object cannot be converted to dict, use config_get or .value instead." + ) + + def __getattribute__(self, item): + if item == "__dict__": + raise TypeError( + "WrappedConfig object cannot be converted to dict, use config_get or .value instead." + ) + return super().__getattribute__(item) + def save(self): # Don't save if the value is the same as the env value and the config value if self.env_value == self.value: @@ -297,6 +314,7 @@ if CUSTOM_NAME: log.exception(e) pass + #################################### # File Upload DIR #################################### @@ -304,6 +322,7 @@ if CUSTOM_NAME: UPLOAD_DIR = f"{DATA_DIR}/uploads" Path(UPLOAD_DIR).mkdir(parents=True, exist_ok=True) + #################################### # Cache DIR #################################### @@ -311,6 +330,7 @@ Path(UPLOAD_DIR).mkdir(parents=True, exist_ok=True) CACHE_DIR = f"{DATA_DIR}/cache" Path(CACHE_DIR).mkdir(parents=True, exist_ok=True) + #################################### # Docs DIR #################################### @@ -351,6 +371,7 @@ if not os.path.exists(LITELLM_CONFIG_PATH): create_config_file(LITELLM_CONFIG_PATH) log.info("Config file created successfully.") + #################################### # OLLAMA_BASE_URL #################################### @@ -381,6 +402,7 @@ if ENV == "prod": elif K8S_FLAG: OLLAMA_BASE_URL = "http://ollama-service.open-webui.svc.cluster.local:11434" + OLLAMA_BASE_URLS = os.environ.get("OLLAMA_BASE_URLS", "") OLLAMA_BASE_URLS = OLLAMA_BASE_URLS if OLLAMA_BASE_URLS != "" else OLLAMA_BASE_URL @@ -396,6 +418,7 @@ OLLAMA_BASE_URLS = WrappedConfig( OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "") OPENAI_API_BASE_URL = os.environ.get("OPENAI_API_BASE_URL", "") + if OPENAI_API_BASE_URL == "": OPENAI_API_BASE_URL = "https://api.openai.com/v1" @@ -614,6 +637,7 @@ RAG_RERANKING_MODEL_TRUST_REMOTE_CODE = ( os.environ.get("RAG_RERANKING_MODEL_TRUST_REMOTE_CODE", "").lower() == "true" ) + if CHROMA_HTTP_HOST != "": CHROMA_CLIENT = chromadb.HttpClient( host=CHROMA_HTTP_HOST, @@ -632,6 +656,7 @@ else: database=CHROMA_DATABASE, ) + # device type embedding models - "cpu" (default), "cuda" (nvidia gpu required) or "mps" (apple silicon) - choosing this right can lead to better performance USE_CUDA = os.environ.get("USE_CUDA_DOCKER", "false") @@ -700,6 +725,7 @@ WHISPER_MODEL_AUTO_UPDATE = ( os.environ.get("WHISPER_MODEL_AUTO_UPDATE", "").lower() == "true" ) + #################################### # Images #################################### @@ -789,6 +815,7 @@ if LITELLM_PROXY_PORT < 0 or LITELLM_PROXY_PORT > 65535: raise ValueError("Invalid port number for LITELLM_PROXY_PORT") LITELLM_PROXY_HOST = os.getenv("LITELLM_PROXY_HOST", "127.0.0.1") + #################################### # Database #################################### From 298e6848b383bf5b3d4590ffa3a95f8dc8450f7b Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Fri, 10 May 2024 15:03:24 +0800 Subject: [PATCH 07/29] feat: switch to config proxy, remove config_get/set --- backend/apps/audio/main.py | 46 +++-- backend/apps/images/main.py | 152 ++++++++-------- backend/apps/ollama/main.py | 60 +++---- backend/apps/openai/main.py | 52 +++--- backend/apps/rag/main.py | 258 +++++++++++++--------------- backend/apps/web/main.py | 22 +-- backend/apps/web/routers/auths.py | 38 ++-- backend/apps/web/routers/configs.py | 9 +- backend/apps/web/routers/users.py | 8 +- backend/config.py | 24 +-- backend/main.py | 50 +++--- 11 files changed, 340 insertions(+), 379 deletions(-) diff --git a/backend/apps/audio/main.py b/backend/apps/audio/main.py index c3dc6a2c4..0f65a551e 100644 --- a/backend/apps/audio/main.py +++ b/backend/apps/audio/main.py @@ -45,8 +45,7 @@ from config import ( AUDIO_OPENAI_API_KEY, AUDIO_OPENAI_API_MODEL, AUDIO_OPENAI_API_VOICE, - config_get, - config_set, + AppConfig, ) log = logging.getLogger(__name__) @@ -61,11 +60,11 @@ app.add_middleware( allow_headers=["*"], ) - -app.state.OPENAI_API_BASE_URL = AUDIO_OPENAI_API_BASE_URL -app.state.OPENAI_API_KEY = AUDIO_OPENAI_API_KEY -app.state.OPENAI_API_MODEL = AUDIO_OPENAI_API_MODEL -app.state.OPENAI_API_VOICE = AUDIO_OPENAI_API_VOICE +app.state.config = AppConfig() +app.state.config.OPENAI_API_BASE_URL = AUDIO_OPENAI_API_BASE_URL +app.state.config.OPENAI_API_KEY = AUDIO_OPENAI_API_KEY +app.state.config.OPENAI_API_MODEL = AUDIO_OPENAI_API_MODEL +app.state.config.OPENAI_API_VOICE = AUDIO_OPENAI_API_VOICE # setting device type for whisper model whisper_device_type = DEVICE_TYPE if DEVICE_TYPE and DEVICE_TYPE == "cuda" else "cpu" @@ -85,10 +84,10 @@ class OpenAIConfigUpdateForm(BaseModel): @app.get("/config") async def get_openai_config(user=Depends(get_admin_user)): return { - "OPENAI_API_BASE_URL": config_get(app.state.OPENAI_API_BASE_URL), - "OPENAI_API_KEY": config_get(app.state.OPENAI_API_KEY), - "OPENAI_API_MODEL": config_get(app.state.OPENAI_API_MODEL), - "OPENAI_API_VOICE": config_get(app.state.OPENAI_API_VOICE), + "OPENAI_API_BASE_URL": app.state.config.OPENAI_API_BASE_URL, + "OPENAI_API_KEY": app.state.config.OPENAI_API_KEY, + "OPENAI_API_MODEL": app.state.config.OPENAI_API_MODEL, + "OPENAI_API_VOICE": app.state.config.OPENAI_API_VOICE, } @@ -99,22 +98,17 @@ async def update_openai_config( if form_data.key == "": raise HTTPException(status_code=400, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND) - config_set(app.state.OPENAI_API_BASE_URL, form_data.url) - config_set(app.state.OPENAI_API_KEY, form_data.key) - config_set(app.state.OPENAI_API_MODEL, form_data.model) - config_set(app.state.OPENAI_API_VOICE, form_data.speaker) - - app.state.OPENAI_API_BASE_URL.save() - app.state.OPENAI_API_KEY.save() - app.state.OPENAI_API_MODEL.save() - app.state.OPENAI_API_VOICE.save() + app.state.config.OPENAI_API_BASE_URL = form_data.url + app.state.config.OPENAI_API_KEY = form_data.key + app.state.config.OPENAI_API_MODEL = form_data.model + app.state.config.OPENAI_API_VOICE = form_data.speaker return { "status": True, - "OPENAI_API_BASE_URL": config_get(app.state.OPENAI_API_BASE_URL), - "OPENAI_API_KEY": config_get(app.state.OPENAI_API_KEY), - "OPENAI_API_MODEL": config_get(app.state.OPENAI_API_MODEL), - "OPENAI_API_VOICE": config_get(app.state.OPENAI_API_VOICE), + "OPENAI_API_BASE_URL": app.state.config.OPENAI_API_BASE_URL, + "OPENAI_API_KEY": app.state.config.OPENAI_API_KEY, + "OPENAI_API_MODEL": app.state.config.OPENAI_API_MODEL, + "OPENAI_API_VOICE": app.state.config.OPENAI_API_VOICE, } @@ -131,13 +125,13 @@ async def speech(request: Request, user=Depends(get_verified_user)): return FileResponse(file_path) headers = {} - headers["Authorization"] = f"Bearer {app.state.OPENAI_API_KEY}" + headers["Authorization"] = f"Bearer {app.state.config.OPENAI_API_KEY}" headers["Content-Type"] = "application/json" r = None try: r = requests.post( - url=f"{app.state.OPENAI_API_BASE_URL}/audio/speech", + url=f"{app.state.config.OPENAI_API_BASE_URL}/audio/speech", data=body, headers=headers, stream=True, diff --git a/backend/apps/images/main.py b/backend/apps/images/main.py index 8ebfb0446..1c309439d 100644 --- a/backend/apps/images/main.py +++ b/backend/apps/images/main.py @@ -42,8 +42,7 @@ from config import ( IMAGE_GENERATION_MODEL, IMAGE_SIZE, IMAGE_STEPS, - config_get, - config_set, + AppConfig, ) @@ -62,28 +61,30 @@ app.add_middleware( allow_headers=["*"], ) -app.state.ENGINE = IMAGE_GENERATION_ENGINE -app.state.ENABLED = ENABLE_IMAGE_GENERATION +app.state.config = AppConfig() -app.state.OPENAI_API_BASE_URL = IMAGES_OPENAI_API_BASE_URL -app.state.OPENAI_API_KEY = IMAGES_OPENAI_API_KEY +app.state.config.ENGINE = IMAGE_GENERATION_ENGINE +app.state.config.ENABLED = ENABLE_IMAGE_GENERATION -app.state.MODEL = IMAGE_GENERATION_MODEL +app.state.config.OPENAI_API_BASE_URL = IMAGES_OPENAI_API_BASE_URL +app.state.config.OPENAI_API_KEY = IMAGES_OPENAI_API_KEY + +app.state.config.MODEL = IMAGE_GENERATION_MODEL -app.state.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL -app.state.COMFYUI_BASE_URL = COMFYUI_BASE_URL +app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL +app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL -app.state.IMAGE_SIZE = IMAGE_SIZE -app.state.IMAGE_STEPS = IMAGE_STEPS +app.state.config.IMAGE_SIZE = IMAGE_SIZE +app.state.config.IMAGE_STEPS = IMAGE_STEPS @app.get("/config") async def get_config(request: Request, user=Depends(get_admin_user)): return { - "engine": config_get(app.state.ENGINE), - "enabled": config_get(app.state.ENABLED), + "engine": app.state.config.ENGINE, + "enabled": app.state.config.ENABLED, } @@ -94,11 +95,11 @@ class ConfigUpdateForm(BaseModel): @app.post("/config/update") async def update_config(form_data: ConfigUpdateForm, user=Depends(get_admin_user)): - config_set(app.state.ENGINE, form_data.engine) - config_set(app.state.ENABLED, form_data.enabled) + app.state.config.ENGINE = form_data.engine + app.state.config.ENABLED = form_data.enabled return { - "engine": config_get(app.state.ENGINE), - "enabled": config_get(app.state.ENABLED), + "engine": app.state.config.ENGINE, + "enabled": app.state.config.ENABLED, } @@ -110,8 +111,8 @@ class EngineUrlUpdateForm(BaseModel): @app.get("/url") async def get_engine_url(user=Depends(get_admin_user)): return { - "AUTOMATIC1111_BASE_URL": config_get(app.state.AUTOMATIC1111_BASE_URL), - "COMFYUI_BASE_URL": config_get(app.state.COMFYUI_BASE_URL), + "AUTOMATIC1111_BASE_URL": app.state.config.AUTOMATIC1111_BASE_URL, + "COMFYUI_BASE_URL": app.state.config.COMFYUI_BASE_URL, } @@ -121,29 +122,29 @@ async def update_engine_url( ): if form_data.AUTOMATIC1111_BASE_URL == None: - config_set(app.state.AUTOMATIC1111_BASE_URL, config_get(AUTOMATIC1111_BASE_URL)) + app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL else: url = form_data.AUTOMATIC1111_BASE_URL.strip("/") try: r = requests.head(url) - config_set(app.state.AUTOMATIC1111_BASE_URL, url) + app.state.config.AUTOMATIC1111_BASE_URL = url except Exception as e: raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) if form_data.COMFYUI_BASE_URL == None: - config_set(app.state.COMFYUI_BASE_URL, COMFYUI_BASE_URL) + app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL else: url = form_data.COMFYUI_BASE_URL.strip("/") try: r = requests.head(url) - config_set(app.state.COMFYUI_BASE_URL, url) + app.state.config.COMFYUI_BASE_URL = url except Exception as e: raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) return { - "AUTOMATIC1111_BASE_URL": config_get(app.state.AUTOMATIC1111_BASE_URL), - "COMFYUI_BASE_URL": config_get(app.state.COMFYUI_BASE_URL), + "AUTOMATIC1111_BASE_URL": app.state.config.AUTOMATIC1111_BASE_URL, + "COMFYUI_BASE_URL": app.state.config.COMFYUI_BASE_URL, "status": True, } @@ -156,8 +157,8 @@ class OpenAIConfigUpdateForm(BaseModel): @app.get("/openai/config") async def get_openai_config(user=Depends(get_admin_user)): return { - "OPENAI_API_BASE_URL": config_get(app.state.OPENAI_API_BASE_URL), - "OPENAI_API_KEY": config_get(app.state.OPENAI_API_KEY), + "OPENAI_API_BASE_URL": app.state.config.OPENAI_API_BASE_URL, + "OPENAI_API_KEY": app.state.config.OPENAI_API_KEY, } @@ -168,13 +169,13 @@ async def update_openai_config( if form_data.key == "": raise HTTPException(status_code=400, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND) - config_set(app.state.OPENAI_API_BASE_URL, form_data.url) - config_set(app.state.OPENAI_API_KEY, form_data.key) + app.state.config.OPENAI_API_BASE_URL = form_data.url + app.state.config.OPENAI_API_KEY = form_data.key return { "status": True, - "OPENAI_API_BASE_URL": config_get(app.state.OPENAI_API_BASE_URL), - "OPENAI_API_KEY": config_get(app.state.OPENAI_API_KEY), + "OPENAI_API_BASE_URL": app.state.config.OPENAI_API_BASE_URL, + "OPENAI_API_KEY": app.state.config.OPENAI_API_KEY, } @@ -184,7 +185,7 @@ class ImageSizeUpdateForm(BaseModel): @app.get("/size") async def get_image_size(user=Depends(get_admin_user)): - return {"IMAGE_SIZE": config_get(app.state.IMAGE_SIZE)} + return {"IMAGE_SIZE": app.state.config.IMAGE_SIZE} @app.post("/size/update") @@ -193,9 +194,9 @@ async def update_image_size( ): pattern = r"^\d+x\d+$" # Regular expression pattern if re.match(pattern, form_data.size): - config_set(app.state.IMAGE_SIZE, form_data.size) + app.state.config.IMAGE_SIZE = form_data.size return { - "IMAGE_SIZE": config_get(app.state.IMAGE_SIZE), + "IMAGE_SIZE": app.state.config.IMAGE_SIZE, "status": True, } else: @@ -211,7 +212,7 @@ class ImageStepsUpdateForm(BaseModel): @app.get("/steps") async def get_image_size(user=Depends(get_admin_user)): - return {"IMAGE_STEPS": config_get(app.state.IMAGE_STEPS)} + return {"IMAGE_STEPS": app.state.config.IMAGE_STEPS} @app.post("/steps/update") @@ -219,9 +220,9 @@ async def update_image_size( form_data: ImageStepsUpdateForm, user=Depends(get_admin_user) ): if form_data.steps >= 0: - config_set(app.state.IMAGE_STEPS, form_data.steps) + app.state.config.IMAGE_STEPS = form_data.steps return { - "IMAGE_STEPS": config_get(app.state.IMAGE_STEPS), + "IMAGE_STEPS": app.state.config.IMAGE_STEPS, "status": True, } else: @@ -234,14 +235,14 @@ async def update_image_size( @app.get("/models") def get_models(user=Depends(get_current_user)): try: - if app.state.ENGINE == "openai": + if app.state.config.ENGINE == "openai": return [ {"id": "dall-e-2", "name": "DALL·E 2"}, {"id": "dall-e-3", "name": "DALL·E 3"}, ] - elif app.state.ENGINE == "comfyui": + elif app.state.config.ENGINE == "comfyui": - r = requests.get(url=f"{app.state.COMFYUI_BASE_URL}/object_info") + r = requests.get(url=f"{app.state.config.COMFYUI_BASE_URL}/object_info") info = r.json() return list( @@ -253,7 +254,7 @@ def get_models(user=Depends(get_current_user)): else: r = requests.get( - url=f"{app.state.AUTOMATIC1111_BASE_URL}/sdapi/v1/sd-models" + url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/sd-models" ) models = r.json() return list( @@ -263,33 +264,29 @@ def get_models(user=Depends(get_current_user)): ) ) except Exception as e: - app.state.ENABLED = False + app.state.config.ENABLED = False raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) @app.get("/models/default") async def get_default_model(user=Depends(get_admin_user)): try: - if app.state.ENGINE == "openai": + if app.state.config.ENGINE == "openai": return { "model": ( - config_get(app.state.MODEL) - if config_get(app.state.MODEL) - else "dall-e-2" - ) - } - elif app.state.ENGINE == "comfyui": - return { - "model": ( - config_get(app.state.MODEL) if config_get(app.state.MODEL) else "" + app.state.config.MODEL if app.state.config.MODEL else "dall-e-2" ) } + elif app.state.config.ENGINE == "comfyui": + return {"model": (app.state.config.MODEL if app.state.config.MODEL else "")} else: - r = requests.get(url=f"{app.state.AUTOMATIC1111_BASE_URL}/sdapi/v1/options") + r = requests.get( + url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options" + ) options = r.json() return {"model": options["sd_model_checkpoint"]} except Exception as e: - config_set(app.state.ENABLED, False) + app.state.config.ENABLED = False raise HTTPException(status_code=400, detail=ERROR_MESSAGES.DEFAULT(e)) @@ -298,17 +295,20 @@ class UpdateModelForm(BaseModel): def set_model_handler(model: str): - if app.state.ENGINE in ["openai", "comfyui"]: - config_set(app.state.MODEL, model) - return config_get(app.state.MODEL) + if app.state.config.ENGINE in ["openai", "comfyui"]: + app.state.config.MODEL = model + return app.state.config.MODEL else: - r = requests.get(url=f"{app.state.AUTOMATIC1111_BASE_URL}/sdapi/v1/options") + r = requests.get( + url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options" + ) options = r.json() if model != options["sd_model_checkpoint"]: options["sd_model_checkpoint"] = model r = requests.post( - url=f"{app.state.AUTOMATIC1111_BASE_URL}/sdapi/v1/options", json=options + url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/options", + json=options, ) return options @@ -397,30 +397,32 @@ def generate_image( user=Depends(get_current_user), ): - width, height = tuple(map(int, config_get(app.state.IMAGE_SIZE).split("x"))) + width, height = tuple(map(int, app.state.config.IMAGE_SIZE).split("x")) r = None try: - if app.state.ENGINE == "openai": + if app.state.config.ENGINE == "openai": headers = {} - headers["Authorization"] = f"Bearer {app.state.OPENAI_API_KEY}" + headers["Authorization"] = f"Bearer {app.state.config.OPENAI_API_KEY}" headers["Content-Type"] = "application/json" data = { - "model": app.state.MODEL if app.state.MODEL != "" else "dall-e-2", + "model": ( + app.state.config.MODEL + if app.state.config.MODEL != "" + else "dall-e-2" + ), "prompt": form_data.prompt, "n": form_data.n, "size": ( - form_data.size - if form_data.size - else config_get(app.state.IMAGE_SIZE) + form_data.size if form_data.size else app.state.config.IMAGE_SIZE ), "response_format": "b64_json", } r = requests.post( - url=f"{app.state.OPENAI_API_BASE_URL}/images/generations", + url=f"{app.state.config.OPENAI_API_BASE_URL}/images/generations", json=data, headers=headers, ) @@ -440,7 +442,7 @@ def generate_image( return images - elif app.state.ENGINE == "comfyui": + elif app.state.config.ENGINE == "comfyui": data = { "prompt": form_data.prompt, @@ -449,8 +451,8 @@ def generate_image( "n": form_data.n, } - if config_get(app.state.IMAGE_STEPS) is not None: - data["steps"] = config_get(app.state.IMAGE_STEPS) + if app.state.config.IMAGE_STEPS is not None: + data["steps"] = app.state.config.IMAGE_STEPS if form_data.negative_prompt is not None: data["negative_prompt"] = form_data.negative_prompt @@ -458,10 +460,10 @@ def generate_image( data = ImageGenerationPayload(**data) res = comfyui_generate_image( - config_get(app.state.MODEL), + app.state.config.MODEL, data, user.id, - config_get(app.state.COMFYUI_BASE_URL), + app.state.config.COMFYUI_BASE_URL, ) log.debug(f"res: {res}") @@ -488,14 +490,14 @@ def generate_image( "height": height, } - if config_get(app.state.IMAGE_STEPS) is not None: - data["steps"] = config_get(app.state.IMAGE_STEPS) + if app.state.config.IMAGE_STEPS is not None: + data["steps"] = app.state.config.IMAGE_STEPS if form_data.negative_prompt is not None: data["negative_prompt"] = form_data.negative_prompt r = requests.post( - url=f"{app.state.AUTOMATIC1111_BASE_URL}/sdapi/v1/txt2img", + url=f"{app.state.config.AUTOMATIC1111_BASE_URL}/sdapi/v1/txt2img", json=data, ) diff --git a/backend/apps/ollama/main.py b/backend/apps/ollama/main.py index 7dfadbb0c..cb80eeed2 100644 --- a/backend/apps/ollama/main.py +++ b/backend/apps/ollama/main.py @@ -46,8 +46,7 @@ from config import ( ENABLE_MODEL_FILTER, MODEL_FILTER_LIST, UPLOAD_DIR, - config_set, - config_get, + AppConfig, ) from utils.misc import calculate_sha256 @@ -63,11 +62,12 @@ app.add_middleware( allow_headers=["*"], ) +app.state.config = AppConfig() app.state.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER app.state.MODEL_FILTER_LIST = MODEL_FILTER_LIST -app.state.OLLAMA_BASE_URLS = OLLAMA_BASE_URLS +app.state.config.OLLAMA_BASE_URLS = OLLAMA_BASE_URLS app.state.MODELS = {} @@ -98,7 +98,7 @@ async def get_status(): @app.get("/urls") async def get_ollama_api_urls(user=Depends(get_admin_user)): - return {"OLLAMA_BASE_URLS": config_get(app.state.OLLAMA_BASE_URLS)} + return {"OLLAMA_BASE_URLS": app.state.config.OLLAMA_BASE_URLS} class UrlUpdateForm(BaseModel): @@ -107,10 +107,10 @@ class UrlUpdateForm(BaseModel): @app.post("/urls/update") async def update_ollama_api_url(form_data: UrlUpdateForm, user=Depends(get_admin_user)): - config_set(app.state.OLLAMA_BASE_URLS, form_data.urls) + app.state.config.OLLAMA_BASE_URLS = form_data.urls - log.info(f"app.state.OLLAMA_BASE_URLS: {app.state.OLLAMA_BASE_URLS}") - return {"OLLAMA_BASE_URLS": config_get(app.state.OLLAMA_BASE_URLS)} + log.info(f"app.state.config.OLLAMA_BASE_URLS: {app.state.config.OLLAMA_BASE_URLS}") + return {"OLLAMA_BASE_URLS": app.state.config.OLLAMA_BASE_URLS} @app.get("/cancel/{request_id}") @@ -155,9 +155,7 @@ def merge_models_lists(model_lists): async def get_all_models(): log.info("get_all_models()") - tasks = [ - fetch_url(f"{url}/api/tags") for url in config_get(app.state.OLLAMA_BASE_URLS) - ] + tasks = [fetch_url(f"{url}/api/tags") for url in app.state.config.OLLAMA_BASE_URLS] responses = await asyncio.gather(*tasks) models = { @@ -183,15 +181,14 @@ async def get_ollama_tags( if user.role == "user": models["models"] = list( filter( - lambda model: model["name"] - in config_get(app.state.MODEL_FILTER_LIST), + lambda model: model["name"] in app.state.MODEL_FILTER_LIST, models["models"], ) ) return models return models else: - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] try: r = requests.request(method="GET", url=f"{url}/api/tags") r.raise_for_status() @@ -222,8 +219,7 @@ async def get_ollama_versions(url_idx: Optional[int] = None): # returns lowest version tasks = [ - fetch_url(f"{url}/api/version") - for url in config_get(app.state.OLLAMA_BASE_URLS) + fetch_url(f"{url}/api/version") for url in app.state.config.OLLAMA_BASE_URLS ] responses = await asyncio.gather(*tasks) responses = list(filter(lambda x: x is not None, responses)) @@ -243,7 +239,7 @@ async def get_ollama_versions(url_idx: Optional[int] = None): detail=ERROR_MESSAGES.OLLAMA_NOT_FOUND, ) else: - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] try: r = requests.request(method="GET", url=f"{url}/api/version") r.raise_for_status() @@ -275,7 +271,7 @@ class ModelNameForm(BaseModel): async def pull_model( form_data: ModelNameForm, url_idx: int = 0, user=Depends(get_admin_user) ): - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") r = None @@ -363,7 +359,7 @@ async def push_model( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.name), ) - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.debug(f"url: {url}") r = None @@ -425,7 +421,7 @@ async def create_model( form_data: CreateModelForm, url_idx: int = 0, user=Depends(get_admin_user) ): log.debug(f"form_data: {form_data}") - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") r = None @@ -498,7 +494,7 @@ async def copy_model( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.source), ) - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") try: @@ -545,7 +541,7 @@ async def delete_model( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.name), ) - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") try: @@ -585,7 +581,7 @@ async def show_model_info(form_data: ModelNameForm, user=Depends(get_verified_us ) url_idx = random.choice(app.state.MODELS[form_data.name]["urls"]) - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") try: @@ -642,7 +638,7 @@ async def generate_embeddings( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") try: @@ -692,7 +688,7 @@ def generate_ollama_embeddings( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") try: @@ -761,7 +757,7 @@ async def generate_completion( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") r = None @@ -864,7 +860,7 @@ async def generate_chat_completion( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") r = None @@ -973,7 +969,7 @@ async def generate_openai_chat_completion( detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model), ) - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] log.info(f"url: {url}") r = None @@ -1072,7 +1068,7 @@ async def get_openai_models( } else: - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] try: r = requests.request(method="GET", url=f"{url}/api/tags") r.raise_for_status() @@ -1206,7 +1202,7 @@ async def download_model( if url_idx == None: url_idx = 0 - url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + url = app.state.config.OLLAMA_BASE_URLS[url_idx] file_name = parse_huggingface_url(form_data.url) @@ -1225,7 +1221,7 @@ async def download_model( def upload_model(file: UploadFile = File(...), url_idx: Optional[int] = None): if url_idx == None: url_idx = 0 - ollama_url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] + ollama_url = app.state.config.OLLAMA_BASE_URLS[url_idx] file_path = f"{UPLOAD_DIR}/{file.filename}" @@ -1290,7 +1286,7 @@ def upload_model(file: UploadFile = File(...), url_idx: Optional[int] = None): # async def upload_model(file: UploadFile = File(), url_idx: Optional[int] = None): # if url_idx == None: # url_idx = 0 -# url = config_get(app.state.OLLAMA_BASE_URLS)[url_idx] +# url = app.state.config.OLLAMA_BASE_URLS[url_idx] # file_location = os.path.join(UPLOAD_DIR, file.filename) # total_size = file.size @@ -1327,7 +1323,7 @@ def upload_model(file: UploadFile = File(...), url_idx: Optional[int] = None): async def deprecated_proxy( path: str, request: Request, user=Depends(get_verified_user) ): - url = config_get(app.state.OLLAMA_BASE_URLS)[0] + url = app.state.config.OLLAMA_BASE_URLS[0] target_url = f"{url}/{path}" body = await request.body() diff --git a/backend/apps/openai/main.py b/backend/apps/openai/main.py index 36fed104c..5112ebb62 100644 --- a/backend/apps/openai/main.py +++ b/backend/apps/openai/main.py @@ -26,8 +26,7 @@ from config import ( CACHE_DIR, ENABLE_MODEL_FILTER, MODEL_FILTER_LIST, - config_set, - config_get, + AppConfig, ) from typing import List, Optional @@ -47,11 +46,13 @@ app.add_middleware( allow_headers=["*"], ) +app.state.config = AppConfig() + app.state.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER app.state.MODEL_FILTER_LIST = MODEL_FILTER_LIST -app.state.OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS -app.state.OPENAI_API_KEYS = OPENAI_API_KEYS +app.state.config.OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS +app.state.config.OPENAI_API_KEYS = OPENAI_API_KEYS app.state.MODELS = {} @@ -77,34 +78,32 @@ class KeysUpdateForm(BaseModel): @app.get("/urls") async def get_openai_urls(user=Depends(get_admin_user)): - return {"OPENAI_API_BASE_URLS": config_get(app.state.OPENAI_API_BASE_URLS)} + return {"OPENAI_API_BASE_URLS": app.state.config.OPENAI_API_BASE_URLS} @app.post("/urls/update") async def update_openai_urls(form_data: UrlsUpdateForm, user=Depends(get_admin_user)): await get_all_models() - config_set(app.state.OPENAI_API_BASE_URLS, form_data.urls) - return {"OPENAI_API_BASE_URLS": config_get(app.state.OPENAI_API_BASE_URLS)} + app.state.config.OPENAI_API_BASE_URLS = form_data.urls + return {"OPENAI_API_BASE_URLS": app.state.config.OPENAI_API_BASE_URLS} @app.get("/keys") async def get_openai_keys(user=Depends(get_admin_user)): - return {"OPENAI_API_KEYS": config_get(app.state.OPENAI_API_KEYS)} + return {"OPENAI_API_KEYS": app.state.config.OPENAI_API_KEYS} @app.post("/keys/update") async def update_openai_key(form_data: KeysUpdateForm, user=Depends(get_admin_user)): - config_set(app.state.OPENAI_API_KEYS, form_data.keys) - return {"OPENAI_API_KEYS": config_get(app.state.OPENAI_API_KEYS)} + app.state.config.OPENAI_API_KEYS = form_data.keys + return {"OPENAI_API_KEYS": app.state.config.OPENAI_API_KEYS} @app.post("/audio/speech") async def speech(request: Request, user=Depends(get_verified_user)): idx = None try: - idx = config_get(app.state.OPENAI_API_BASE_URLS).index( - "https://api.openai.com/v1" - ) + idx = app.state.config.OPENAI_API_BASE_URLS.index("https://api.openai.com/v1") body = await request.body() name = hashlib.sha256(body).hexdigest() @@ -118,15 +117,13 @@ async def speech(request: Request, user=Depends(get_verified_user)): return FileResponse(file_path) headers = {} - headers["Authorization"] = ( - f"Bearer {config_get(app.state.OPENAI_API_KEYS)[idx]}" - ) + headers["Authorization"] = f"Bearer {app.state.config.OPENAI_API_KEYS[idx]}" headers["Content-Type"] = "application/json" r = None try: r = requests.post( - url=f"{config_get(app.state.OPENAI_API_BASE_URLS)[idx]}/audio/speech", + url=f"{app.state.config.OPENAI_API_BASE_URLS[idx]}/audio/speech", data=body, headers=headers, stream=True, @@ -187,7 +184,7 @@ def merge_models_lists(model_lists): {**model, "urlIdx": idx} for model in models if "api.openai.com" - not in config_get(app.state.OPENAI_API_BASE_URLS)[idx] + not in app.state.config.OPENAI_API_BASE_URLS[idx] or "gpt" in model["id"] ] ) @@ -199,14 +196,14 @@ async def get_all_models(): log.info("get_all_models()") if ( - len(config_get(app.state.OPENAI_API_KEYS)) == 1 - and config_get(app.state.OPENAI_API_KEYS)[0] == "" + len(app.state.config.OPENAI_API_KEYS) == 1 + and app.state.config.OPENAI_API_KEYS[0] == "" ): models = {"data": []} else: tasks = [ - fetch_url(f"{url}/models", config_get(app.state.OPENAI_API_KEYS)[idx]) - for idx, url in enumerate(config_get(app.state.OPENAI_API_BASE_URLS)) + fetch_url(f"{url}/models", app.state.config.OPENAI_API_KEYS[idx]) + for idx, url in enumerate(app.state.config.OPENAI_API_BASE_URLS) ] responses = await asyncio.gather(*tasks) @@ -238,19 +235,18 @@ async def get_all_models(): async def get_models(url_idx: Optional[int] = None, user=Depends(get_current_user)): if url_idx == None: models = await get_all_models() - if config_get(app.state.ENABLE_MODEL_FILTER): + if app.state.ENABLE_MODEL_FILTER: if user.role == "user": models["data"] = list( filter( - lambda model: model["id"] - in config_get(app.state.MODEL_FILTER_LIST), + lambda model: model["id"] in app.state.MODEL_FILTER_LIST, models["data"], ) ) return models return models else: - url = config_get(app.state.OPENAI_API_BASE_URLS)[url_idx] + url = app.state.config.OPENAI_API_BASE_URLS[url_idx] r = None @@ -314,8 +310,8 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)): except json.JSONDecodeError as e: log.error("Error loading request body into a dictionary:", e) - url = config_get(app.state.OPENAI_API_BASE_URLS)[idx] - key = config_get(app.state.OPENAI_API_KEYS)[idx] + url = app.state.config.OPENAI_API_BASE_URLS[idx] + key = app.state.config.OPENAI_API_KEYS[idx] target_url = f"{url}/{path}" diff --git a/backend/apps/rag/main.py b/backend/apps/rag/main.py index f05447a66..d2c3964ae 100644 --- a/backend/apps/rag/main.py +++ b/backend/apps/rag/main.py @@ -93,8 +93,7 @@ from config import ( RAG_TEMPLATE, ENABLE_RAG_LOCAL_WEB_FETCH, YOUTUBE_LOADER_LANGUAGE, - config_set, - config_get, + AppConfig, ) from constants import ERROR_MESSAGES @@ -104,30 +103,32 @@ log.setLevel(SRC_LOG_LEVELS["RAG"]) app = FastAPI() -app.state.TOP_K = RAG_TOP_K -app.state.RELEVANCE_THRESHOLD = RAG_RELEVANCE_THRESHOLD +app.state.config = AppConfig() -app.state.ENABLE_RAG_HYBRID_SEARCH = ENABLE_RAG_HYBRID_SEARCH -app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = ( +app.state.config.TOP_K = RAG_TOP_K +app.state.config.RELEVANCE_THRESHOLD = RAG_RELEVANCE_THRESHOLD + +app.state.config.ENABLE_RAG_HYBRID_SEARCH = ENABLE_RAG_HYBRID_SEARCH +app.state.config.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = ( ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION ) -app.state.CHUNK_SIZE = CHUNK_SIZE -app.state.CHUNK_OVERLAP = CHUNK_OVERLAP +app.state.config.CHUNK_SIZE = CHUNK_SIZE +app.state.config.CHUNK_OVERLAP = CHUNK_OVERLAP -app.state.RAG_EMBEDDING_ENGINE = RAG_EMBEDDING_ENGINE -app.state.RAG_EMBEDDING_MODEL = RAG_EMBEDDING_MODEL -app.state.RAG_RERANKING_MODEL = RAG_RERANKING_MODEL -app.state.RAG_TEMPLATE = RAG_TEMPLATE +app.state.config.RAG_EMBEDDING_ENGINE = RAG_EMBEDDING_ENGINE +app.state.config.RAG_EMBEDDING_MODEL = RAG_EMBEDDING_MODEL +app.state.config.RAG_RERANKING_MODEL = RAG_RERANKING_MODEL +app.state.config.RAG_TEMPLATE = RAG_TEMPLATE -app.state.OPENAI_API_BASE_URL = RAG_OPENAI_API_BASE_URL -app.state.OPENAI_API_KEY = RAG_OPENAI_API_KEY +app.state.config.OPENAI_API_BASE_URL = RAG_OPENAI_API_BASE_URL +app.state.config.OPENAI_API_KEY = RAG_OPENAI_API_KEY -app.state.PDF_EXTRACT_IMAGES = PDF_EXTRACT_IMAGES +app.state.config.PDF_EXTRACT_IMAGES = PDF_EXTRACT_IMAGES -app.state.YOUTUBE_LOADER_LANGUAGE = YOUTUBE_LOADER_LANGUAGE +app.state.config.YOUTUBE_LOADER_LANGUAGE = YOUTUBE_LOADER_LANGUAGE app.state.YOUTUBE_LOADER_TRANSLATION = None @@ -135,7 +136,7 @@ def update_embedding_model( embedding_model: str, update_model: bool = False, ): - if embedding_model and config_get(app.state.RAG_EMBEDDING_ENGINE) == "": + if embedding_model and app.state.config.RAG_EMBEDDING_ENGINE == "": app.state.sentence_transformer_ef = sentence_transformers.SentenceTransformer( get_model_path(embedding_model, update_model), device=DEVICE_TYPE, @@ -160,22 +161,22 @@ def update_reranking_model( update_embedding_model( - config_get(app.state.RAG_EMBEDDING_MODEL), + app.state.config.RAG_EMBEDDING_MODEL, RAG_EMBEDDING_MODEL_AUTO_UPDATE, ) update_reranking_model( - config_get(app.state.RAG_RERANKING_MODEL), + app.state.config.RAG_RERANKING_MODEL, RAG_RERANKING_MODEL_AUTO_UPDATE, ) app.state.EMBEDDING_FUNCTION = get_embedding_function( - config_get(app.state.RAG_EMBEDDING_ENGINE), - config_get(app.state.RAG_EMBEDDING_MODEL), + app.state.config.RAG_EMBEDDING_ENGINE, + app.state.config.RAG_EMBEDDING_MODEL, app.state.sentence_transformer_ef, - config_get(app.state.OPENAI_API_KEY), - config_get(app.state.OPENAI_API_BASE_URL), + app.state.config.OPENAI_API_KEY, + app.state.config.OPENAI_API_BASE_URL, ) origins = ["*"] @@ -202,12 +203,12 @@ class UrlForm(CollectionNameForm): async def get_status(): return { "status": True, - "chunk_size": config_get(app.state.CHUNK_SIZE), - "chunk_overlap": config_get(app.state.CHUNK_OVERLAP), - "template": config_get(app.state.RAG_TEMPLATE), - "embedding_engine": config_get(app.state.RAG_EMBEDDING_ENGINE), - "embedding_model": config_get(app.state.RAG_EMBEDDING_MODEL), - "reranking_model": config_get(app.state.RAG_RERANKING_MODEL), + "chunk_size": app.state.config.CHUNK_SIZE, + "chunk_overlap": app.state.config.CHUNK_OVERLAP, + "template": app.state.config.RAG_TEMPLATE, + "embedding_engine": app.state.config.RAG_EMBEDDING_ENGINE, + "embedding_model": app.state.config.RAG_EMBEDDING_MODEL, + "reranking_model": app.state.config.RAG_RERANKING_MODEL, } @@ -215,11 +216,11 @@ async def get_status(): async def get_embedding_config(user=Depends(get_admin_user)): return { "status": True, - "embedding_engine": config_get(app.state.RAG_EMBEDDING_ENGINE), - "embedding_model": config_get(app.state.RAG_EMBEDDING_MODEL), + "embedding_engine": app.state.config.RAG_EMBEDDING_ENGINE, + "embedding_model": app.state.config.RAG_EMBEDDING_MODEL, "openai_config": { - "url": config_get(app.state.OPENAI_API_BASE_URL), - "key": config_get(app.state.OPENAI_API_KEY), + "url": app.state.config.OPENAI_API_BASE_URL, + "key": app.state.config.OPENAI_API_KEY, }, } @@ -228,7 +229,7 @@ async def get_embedding_config(user=Depends(get_admin_user)): async def get_reraanking_config(user=Depends(get_admin_user)): return { "status": True, - "reranking_model": config_get(app.state.RAG_RERANKING_MODEL), + "reranking_model": app.state.config.RAG_RERANKING_MODEL, } @@ -248,34 +249,34 @@ async def update_embedding_config( form_data: EmbeddingModelUpdateForm, user=Depends(get_admin_user) ): log.info( - f"Updating embedding model: {app.state.RAG_EMBEDDING_MODEL} to {form_data.embedding_model}" + f"Updating embedding model: {app.state.config.RAG_EMBEDDING_MODEL} to {form_data.embedding_model}" ) try: - config_set(app.state.RAG_EMBEDDING_ENGINE, form_data.embedding_engine) - config_set(app.state.RAG_EMBEDDING_MODEL, form_data.embedding_model) + app.state.config.RAG_EMBEDDING_ENGINE = form_data.embedding_engine + app.state.config.RAG_EMBEDDING_MODEL = form_data.embedding_model - if config_get(app.state.RAG_EMBEDDING_ENGINE) in ["ollama", "openai"]: + if app.state.config.RAG_EMBEDDING_ENGINE in ["ollama", "openai"]: if form_data.openai_config != None: - config_set(app.state.OPENAI_API_BASE_URL, form_data.openai_config.url) - config_set(app.state.OPENAI_API_KEY, form_data.openai_config.key) + app.state.config.OPENAI_API_BASE_URL = form_data.openai_config.url + app.state.config.OPENAI_API_KEY = form_data.openai_config.key - update_embedding_model(config_get(app.state.RAG_EMBEDDING_MODEL), True) + update_embedding_model(app.state.config.RAG_EMBEDDING_MODEL), True app.state.EMBEDDING_FUNCTION = get_embedding_function( - config_get(app.state.RAG_EMBEDDING_ENGINE), - config_get(app.state.RAG_EMBEDDING_MODEL), + app.state.config.RAG_EMBEDDING_ENGINE, + app.state.config.RAG_EMBEDDING_MODEL, app.state.sentence_transformer_ef, - config_get(app.state.OPENAI_API_KEY), - config_get(app.state.OPENAI_API_BASE_URL), + app.state.config.OPENAI_API_KEY, + app.state.config.OPENAI_API_BASE_URL, ) return { "status": True, - "embedding_engine": config_get(app.state.RAG_EMBEDDING_ENGINE), - "embedding_model": config_get(app.state.RAG_EMBEDDING_MODEL), + "embedding_engine": app.state.config.RAG_EMBEDDING_ENGINE, + "embedding_model": app.state.config.RAG_EMBEDDING_MODEL, "openai_config": { - "url": config_get(app.state.OPENAI_API_BASE_URL), - "key": config_get(app.state.OPENAI_API_KEY), + "url": app.state.config.OPENAI_API_BASE_URL, + "key": app.state.config.OPENAI_API_KEY, }, } except Exception as e: @@ -295,16 +296,16 @@ async def update_reranking_config( form_data: RerankingModelUpdateForm, user=Depends(get_admin_user) ): log.info( - f"Updating reranking model: {app.state.RAG_RERANKING_MODEL} to {form_data.reranking_model}" + f"Updating reranking model: {app.state.config.RAG_RERANKING_MODEL} to {form_data.reranking_model}" ) try: - config_set(app.state.RAG_RERANKING_MODEL, form_data.reranking_model) + app.state.config.RAG_RERANKING_MODEL = form_data.reranking_model - update_reranking_model(config_get(app.state.RAG_RERANKING_MODEL), True) + update_reranking_model(app.state.config.RAG_RERANKING_MODEL), True return { "status": True, - "reranking_model": config_get(app.state.RAG_RERANKING_MODEL), + "reranking_model": app.state.config.RAG_RERANKING_MODEL, } except Exception as e: log.exception(f"Problem updating reranking model: {e}") @@ -318,16 +319,14 @@ async def update_reranking_config( async def get_rag_config(user=Depends(get_admin_user)): return { "status": True, - "pdf_extract_images": config_get(app.state.PDF_EXTRACT_IMAGES), + "pdf_extract_images": app.state.config.PDF_EXTRACT_IMAGES, "chunk": { - "chunk_size": config_get(app.state.CHUNK_SIZE), - "chunk_overlap": config_get(app.state.CHUNK_OVERLAP), + "chunk_size": app.state.config.CHUNK_SIZE, + "chunk_overlap": app.state.config.CHUNK_OVERLAP, }, - "web_loader_ssl_verification": config_get( - app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION - ), + "web_loader_ssl_verification": app.state.config.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION, "youtube": { - "language": config_get(app.state.YOUTUBE_LOADER_LANGUAGE), + "language": app.state.config.YOUTUBE_LOADER_LANGUAGE, "translation": app.state.YOUTUBE_LOADER_TRANSLATION, }, } @@ -352,49 +351,34 @@ class ConfigUpdateForm(BaseModel): @app.post("/config/update") async def update_rag_config(form_data: ConfigUpdateForm, user=Depends(get_admin_user)): - config_set( - app.state.PDF_EXTRACT_IMAGES, - ( - form_data.pdf_extract_images - if form_data.pdf_extract_images is not None - else config_get(app.state.PDF_EXTRACT_IMAGES) - ), + app.state.config.PDF_EXTRACT_IMAGES = ( + form_data.pdf_extract_images + if form_data.pdf_extract_images is not None + else app.state.config.PDF_EXTRACT_IMAGES ) - config_set( - app.state.CHUNK_SIZE, - ( - form_data.chunk.chunk_size - if form_data.chunk is not None - else config_get(app.state.CHUNK_SIZE) - ), + app.state.config.CHUNK_SIZE = ( + form_data.chunk.chunk_size + if form_data.chunk is not None + else app.state.config.CHUNK_SIZE ) - config_set( - app.state.CHUNK_OVERLAP, - ( - form_data.chunk.chunk_overlap - if form_data.chunk is not None - else config_get(app.state.CHUNK_OVERLAP) - ), + app.state.config.CHUNK_OVERLAP = ( + form_data.chunk.chunk_overlap + if form_data.chunk is not None + else app.state.config.CHUNK_OVERLAP ) - config_set( - app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION, - ( - form_data.web_loader_ssl_verification - if form_data.web_loader_ssl_verification != None - else config_get(app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION) - ), + app.state.config.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = ( + form_data.web_loader_ssl_verification + if form_data.web_loader_ssl_verification != None + else app.state.config.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION ) - config_set( - app.state.YOUTUBE_LOADER_LANGUAGE, - ( - form_data.youtube.language - if form_data.youtube is not None - else config_get(app.state.YOUTUBE_LOADER_LANGUAGE) - ), + app.state.config.YOUTUBE_LOADER_LANGUAGE = ( + form_data.youtube.language + if form_data.youtube is not None + else app.state.config.YOUTUBE_LOADER_LANGUAGE ) app.state.YOUTUBE_LOADER_TRANSLATION = ( @@ -405,16 +389,14 @@ async def update_rag_config(form_data: ConfigUpdateForm, user=Depends(get_admin_ return { "status": True, - "pdf_extract_images": config_get(app.state.PDF_EXTRACT_IMAGES), + "pdf_extract_images": app.state.config.PDF_EXTRACT_IMAGES, "chunk": { - "chunk_size": config_get(app.state.CHUNK_SIZE), - "chunk_overlap": config_get(app.state.CHUNK_OVERLAP), + "chunk_size": app.state.config.CHUNK_SIZE, + "chunk_overlap": app.state.config.CHUNK_OVERLAP, }, - "web_loader_ssl_verification": config_get( - app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION - ), + "web_loader_ssl_verification": app.state.config.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION, "youtube": { - "language": config_get(app.state.YOUTUBE_LOADER_LANGUAGE), + "language": app.state.config.YOUTUBE_LOADER_LANGUAGE, "translation": app.state.YOUTUBE_LOADER_TRANSLATION, }, } @@ -424,7 +406,7 @@ async def update_rag_config(form_data: ConfigUpdateForm, user=Depends(get_admin_ async def get_rag_template(user=Depends(get_current_user)): return { "status": True, - "template": config_get(app.state.RAG_TEMPLATE), + "template": app.state.config.RAG_TEMPLATE, } @@ -432,10 +414,10 @@ async def get_rag_template(user=Depends(get_current_user)): async def get_query_settings(user=Depends(get_admin_user)): return { "status": True, - "template": config_get(app.state.RAG_TEMPLATE), - "k": config_get(app.state.TOP_K), - "r": config_get(app.state.RELEVANCE_THRESHOLD), - "hybrid": config_get(app.state.ENABLE_RAG_HYBRID_SEARCH), + "template": app.state.config.RAG_TEMPLATE, + "k": app.state.config.TOP_K, + "r": app.state.config.RELEVANCE_THRESHOLD, + "hybrid": app.state.config.ENABLE_RAG_HYBRID_SEARCH, } @@ -450,22 +432,20 @@ class QuerySettingsForm(BaseModel): async def update_query_settings( form_data: QuerySettingsForm, user=Depends(get_admin_user) ): - config_set( - app.state.RAG_TEMPLATE, + app.state.config.RAG_TEMPLATE = ( form_data.template if form_data.template else RAG_TEMPLATE, ) - config_set(app.state.TOP_K, form_data.k if form_data.k else 4) - config_set(app.state.RELEVANCE_THRESHOLD, form_data.r if form_data.r else 0.0) - config_set( - app.state.ENABLE_RAG_HYBRID_SEARCH, + app.state.config.TOP_K = form_data.k if form_data.k else 4 + app.state.config.RELEVANCE_THRESHOLD = form_data.r if form_data.r else 0.0 + app.state.config.ENABLE_RAG_HYBRID_SEARCH = ( form_data.hybrid if form_data.hybrid else False, ) return { "status": True, - "template": config_get(app.state.RAG_TEMPLATE), - "k": config_get(app.state.TOP_K), - "r": config_get(app.state.RELEVANCE_THRESHOLD), - "hybrid": config_get(app.state.ENABLE_RAG_HYBRID_SEARCH), + "template": app.state.config.RAG_TEMPLATE, + "k": app.state.config.TOP_K, + "r": app.state.config.RELEVANCE_THRESHOLD, + "hybrid": app.state.config.ENABLE_RAG_HYBRID_SEARCH, } @@ -483,17 +463,15 @@ def query_doc_handler( user=Depends(get_current_user), ): try: - if config_get(app.state.ENABLE_RAG_HYBRID_SEARCH): + if app.state.config.ENABLE_RAG_HYBRID_SEARCH: return query_doc_with_hybrid_search( collection_name=form_data.collection_name, query=form_data.query, embedding_function=app.state.EMBEDDING_FUNCTION, - k=form_data.k if form_data.k else config_get(app.state.TOP_K), + k=form_data.k if form_data.k else app.state.config.TOP_K, reranking_function=app.state.sentence_transformer_rf, r=( - form_data.r - if form_data.r - else config_get(app.state.RELEVANCE_THRESHOLD) + form_data.r if form_data.r else app.state.config.RELEVANCE_THRESHOLD ), ) else: @@ -501,7 +479,7 @@ def query_doc_handler( collection_name=form_data.collection_name, query=form_data.query, embedding_function=app.state.EMBEDDING_FUNCTION, - k=form_data.k if form_data.k else config_get(app.state.TOP_K), + k=form_data.k if form_data.k else app.state.config.TOP_K, ) except Exception as e: log.exception(e) @@ -525,17 +503,15 @@ def query_collection_handler( user=Depends(get_current_user), ): try: - if config_get(app.state.ENABLE_RAG_HYBRID_SEARCH): + if app.state.config.ENABLE_RAG_HYBRID_SEARCH: return query_collection_with_hybrid_search( collection_names=form_data.collection_names, query=form_data.query, embedding_function=app.state.EMBEDDING_FUNCTION, - k=form_data.k if form_data.k else config_get(app.state.TOP_K), + k=form_data.k if form_data.k else app.state.config.TOP_K, reranking_function=app.state.sentence_transformer_rf, r=( - form_data.r - if form_data.r - else config_get(app.state.RELEVANCE_THRESHOLD) + form_data.r if form_data.r else app.state.config.RELEVANCE_THRESHOLD ), ) else: @@ -543,7 +519,7 @@ def query_collection_handler( collection_names=form_data.collection_names, query=form_data.query, embedding_function=app.state.EMBEDDING_FUNCTION, - k=form_data.k if form_data.k else config_get(app.state.TOP_K), + k=form_data.k if form_data.k else app.state.config.TOP_K, ) except Exception as e: @@ -560,8 +536,8 @@ def store_youtube_video(form_data: UrlForm, user=Depends(get_current_user)): loader = YoutubeLoader.from_youtube_url( form_data.url, add_video_info=True, - language=config_get(app.state.YOUTUBE_LOADER_LANGUAGE), - translation=config_get(app.state.YOUTUBE_LOADER_TRANSLATION), + language=app.state.config.YOUTUBE_LOADER_LANGUAGE, + translation=app.state.YOUTUBE_LOADER_TRANSLATION, ) data = loader.load() @@ -589,7 +565,7 @@ def store_web(form_data: UrlForm, user=Depends(get_current_user)): try: loader = get_web_loader( form_data.url, - verify_ssl=config_get(app.state.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION), + verify_ssl=app.state.config.ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION, ) data = loader.load() @@ -645,8 +621,8 @@ def resolve_hostname(hostname): def store_data_in_vector_db(data, collection_name, overwrite: bool = False) -> bool: text_splitter = RecursiveCharacterTextSplitter( - chunk_size=config_get(app.state.CHUNK_SIZE), - chunk_overlap=config_get(app.state.CHUNK_OVERLAP), + chunk_size=app.state.config.CHUNK_SIZE, + chunk_overlap=app.state.config.CHUNK_OVERLAP, add_start_index=True, ) @@ -663,8 +639,8 @@ def store_text_in_vector_db( text, metadata, collection_name, overwrite: bool = False ) -> bool: text_splitter = RecursiveCharacterTextSplitter( - chunk_size=config_get(app.state.CHUNK_SIZE), - chunk_overlap=config_get(app.state.CHUNK_OVERLAP), + chunk_size=app.state.config.CHUNK_SIZE, + chunk_overlap=app.state.config.CHUNK_OVERLAP, add_start_index=True, ) docs = text_splitter.create_documents([text], metadatas=[metadata]) @@ -687,11 +663,11 @@ def store_docs_in_vector_db(docs, collection_name, overwrite: bool = False) -> b collection = CHROMA_CLIENT.create_collection(name=collection_name) embedding_func = get_embedding_function( - config_get(app.state.RAG_EMBEDDING_ENGINE), - config_get(app.state.RAG_EMBEDDING_MODEL), + app.state.config.RAG_EMBEDDING_ENGINE, + app.state.config.RAG_EMBEDDING_MODEL, app.state.sentence_transformer_ef, - config_get(app.state.OPENAI_API_KEY), - config_get(app.state.OPENAI_API_BASE_URL), + app.state.config.OPENAI_API_KEY, + app.state.config.OPENAI_API_BASE_URL, ) embedding_texts = list(map(lambda x: x.replace("\n", " "), texts)) @@ -766,7 +742,7 @@ def get_loader(filename: str, file_content_type: str, file_path: str): if file_ext == "pdf": loader = PyPDFLoader( - file_path, extract_images=config_get(app.state.PDF_EXTRACT_IMAGES) + file_path, extract_images=app.state.config.PDF_EXTRACT_IMAGES ) elif file_ext == "csv": loader = CSVLoader(file_path) diff --git a/backend/apps/web/main.py b/backend/apps/web/main.py index 2bed33543..755e3911b 100644 --- a/backend/apps/web/main.py +++ b/backend/apps/web/main.py @@ -22,21 +22,23 @@ from config import ( WEBHOOK_URL, WEBUI_AUTH_TRUSTED_EMAIL_HEADER, JWT_EXPIRES_IN, - config_get, + AppConfig, ) app = FastAPI() origins = ["*"] -app.state.ENABLE_SIGNUP = ENABLE_SIGNUP -app.state.JWT_EXPIRES_IN = JWT_EXPIRES_IN +app.state.config = AppConfig() -app.state.DEFAULT_MODELS = DEFAULT_MODELS -app.state.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS -app.state.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE -app.state.USER_PERMISSIONS = USER_PERMISSIONS -app.state.WEBHOOK_URL = WEBHOOK_URL +app.state.config.ENABLE_SIGNUP = ENABLE_SIGNUP +app.state.config.JWT_EXPIRES_IN = JWT_EXPIRES_IN + +app.state.config.DEFAULT_MODELS = DEFAULT_MODELS +app.state.config.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS +app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE +app.state.config.USER_PERMISSIONS = USER_PERMISSIONS +app.state.config.WEBHOOK_URL = WEBHOOK_URL app.state.AUTH_TRUSTED_EMAIL_HEADER = WEBUI_AUTH_TRUSTED_EMAIL_HEADER app.add_middleware( @@ -63,6 +65,6 @@ async def get_status(): return { "status": True, "auth": WEBUI_AUTH, - "default_models": config_get(app.state.DEFAULT_MODELS), - "default_prompt_suggestions": config_get(app.state.DEFAULT_PROMPT_SUGGESTIONS), + "default_models": app.state.config.DEFAULT_MODELS, + "default_prompt_suggestions": app.state.config.DEFAULT_PROMPT_SUGGESTIONS, } diff --git a/backend/apps/web/routers/auths.py b/backend/apps/web/routers/auths.py index 0bc4967f9..998e74659 100644 --- a/backend/apps/web/routers/auths.py +++ b/backend/apps/web/routers/auths.py @@ -33,7 +33,7 @@ from utils.utils import ( from utils.misc import parse_duration, validate_email_format from utils.webhook import post_webhook from constants import ERROR_MESSAGES, WEBHOOK_MESSAGES -from config import WEBUI_AUTH, WEBUI_AUTH_TRUSTED_EMAIL_HEADER, config_get, config_set +from config import WEBUI_AUTH, WEBUI_AUTH_TRUSTED_EMAIL_HEADER router = APIRouter() @@ -140,7 +140,7 @@ async def signin(request: Request, form_data: SigninForm): if user: token = create_token( data={"id": user.id}, - expires_delta=parse_duration(config_get(request.app.state.JWT_EXPIRES_IN)), + expires_delta=parse_duration(request.app.state.config.JWT_EXPIRES_IN), ) return { @@ -163,7 +163,7 @@ async def signin(request: Request, form_data: SigninForm): @router.post("/signup", response_model=SigninResponse) async def signup(request: Request, form_data: SignupForm): - if not config_get(request.app.state.ENABLE_SIGNUP) and WEBUI_AUTH: + if not request.app.state.config.ENABLE_SIGNUP and WEBUI_AUTH: raise HTTPException( status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED ) @@ -180,7 +180,7 @@ async def signup(request: Request, form_data: SignupForm): role = ( "admin" if Users.get_num_users() == 0 - else config_get(request.app.state.DEFAULT_USER_ROLE) + else request.app.state.config.DEFAULT_USER_ROLE ) hashed = get_password_hash(form_data.password) user = Auths.insert_new_auth( @@ -194,15 +194,13 @@ async def signup(request: Request, form_data: SignupForm): if user: token = create_token( data={"id": user.id}, - expires_delta=parse_duration( - config_get(request.app.state.JWT_EXPIRES_IN) - ), + expires_delta=parse_duration(request.app.state.config.JWT_EXPIRES_IN), ) # response.set_cookie(key='token', value=token, httponly=True) - if config_get(request.app.state.WEBHOOK_URL): + if request.app.state.config.WEBHOOK_URL: post_webhook( - config_get(request.app.state.WEBHOOK_URL), + request.app.state.config.WEBHOOK_URL, WEBHOOK_MESSAGES.USER_SIGNUP(user.name), { "action": "signup", @@ -278,15 +276,13 @@ async def add_user(form_data: AddUserForm, user=Depends(get_admin_user)): @router.get("/signup/enabled", response_model=bool) async def get_sign_up_status(request: Request, user=Depends(get_admin_user)): - return config_get(request.app.state.ENABLE_SIGNUP) + return request.app.state.config.ENABLE_SIGNUP @router.get("/signup/enabled/toggle", response_model=bool) async def toggle_sign_up(request: Request, user=Depends(get_admin_user)): - config_set( - request.app.state.ENABLE_SIGNUP, not config_get(request.app.state.ENABLE_SIGNUP) - ) - return config_get(request.app.state.ENABLE_SIGNUP) + request.app.state.config.ENABLE_SIGNUP = not request.app.state.config.ENABLE_SIGNUP + return request.app.state.config.ENABLE_SIGNUP ############################ @@ -296,7 +292,7 @@ async def toggle_sign_up(request: Request, user=Depends(get_admin_user)): @router.get("/signup/user/role") async def get_default_user_role(request: Request, user=Depends(get_admin_user)): - return config_get(request.app.state.DEFAULT_USER_ROLE) + return request.app.state.config.DEFAULT_USER_ROLE class UpdateRoleForm(BaseModel): @@ -308,8 +304,8 @@ async def update_default_user_role( request: Request, form_data: UpdateRoleForm, user=Depends(get_admin_user) ): if form_data.role in ["pending", "user", "admin"]: - config_set(request.app.state.DEFAULT_USER_ROLE, form_data.role) - return config_get(request.app.state.DEFAULT_USER_ROLE) + request.app.state.config.DEFAULT_USER_ROLE = form_data.role + return request.app.state.config.DEFAULT_USER_ROLE ############################ @@ -319,7 +315,7 @@ async def update_default_user_role( @router.get("/token/expires") async def get_token_expires_duration(request: Request, user=Depends(get_admin_user)): - return config_get(request.app.state.JWT_EXPIRES_IN) + return request.app.state.config.JWT_EXPIRES_IN class UpdateJWTExpiresDurationForm(BaseModel): @@ -336,10 +332,10 @@ async def update_token_expires_duration( # Check if the input string matches the pattern if re.match(pattern, form_data.duration): - config_set(request.app.state.JWT_EXPIRES_IN, form_data.duration) - return config_get(request.app.state.JWT_EXPIRES_IN) + request.app.state.config.JWT_EXPIRES_IN = form_data.duration + return request.app.state.config.JWT_EXPIRES_IN else: - return config_get(request.app.state.JWT_EXPIRES_IN) + return request.app.state.config.JWT_EXPIRES_IN ############################ diff --git a/backend/apps/web/routers/configs.py b/backend/apps/web/routers/configs.py index d726cd2dc..143ed5e0a 100644 --- a/backend/apps/web/routers/configs.py +++ b/backend/apps/web/routers/configs.py @@ -9,7 +9,6 @@ import time import uuid from apps.web.models.users import Users -from config import config_set, config_get from utils.utils import ( get_password_hash, @@ -45,8 +44,8 @@ class SetDefaultSuggestionsForm(BaseModel): async def set_global_default_models( request: Request, form_data: SetDefaultModelsForm, user=Depends(get_admin_user) ): - config_set(request.app.state.DEFAULT_MODELS, form_data.models) - return config_get(request.app.state.DEFAULT_MODELS) + request.app.state.config.DEFAULT_MODELS = form_data.models + return request.app.state.config.DEFAULT_MODELS @router.post("/default/suggestions", response_model=List[PromptSuggestion]) @@ -56,5 +55,5 @@ async def set_global_default_suggestions( user=Depends(get_admin_user), ): data = form_data.model_dump() - config_set(request.app.state.DEFAULT_PROMPT_SUGGESTIONS, data["suggestions"]) - return config_get(request.app.state.DEFAULT_PROMPT_SUGGESTIONS) + request.app.state.config.DEFAULT_PROMPT_SUGGESTIONS = data["suggestions"] + return request.app.state.config.DEFAULT_PROMPT_SUGGESTIONS diff --git a/backend/apps/web/routers/users.py b/backend/apps/web/routers/users.py index 302432540..d87854e89 100644 --- a/backend/apps/web/routers/users.py +++ b/backend/apps/web/routers/users.py @@ -15,7 +15,7 @@ from apps.web.models.auths import Auths from utils.utils import get_current_user, get_password_hash, get_admin_user from constants import ERROR_MESSAGES -from config import SRC_LOG_LEVELS, config_set, config_get +from config import SRC_LOG_LEVELS log = logging.getLogger(__name__) log.setLevel(SRC_LOG_LEVELS["MODELS"]) @@ -39,15 +39,15 @@ async def get_users(skip: int = 0, limit: int = 50, user=Depends(get_admin_user) @router.get("/permissions/user") async def get_user_permissions(request: Request, user=Depends(get_admin_user)): - return config_get(request.app.state.USER_PERMISSIONS) + return request.app.state.config.USER_PERMISSIONS @router.post("/permissions/user") async def update_user_permissions( request: Request, form_data: dict, user=Depends(get_admin_user) ): - config_set(request.app.state.USER_PERMISSIONS, form_data) - return config_get(request.app.state.USER_PERMISSIONS) + request.app.state.config.USER_PERMISSIONS = form_data + return request.app.state.config.USER_PERMISSIONS ############################ diff --git a/backend/config.py b/backend/config.py index 9e7a9ef90..845a812ce 100644 --- a/backend/config.py +++ b/backend/config.py @@ -246,19 +246,21 @@ class WrappedConfig(Generic[T]): self.config_value = self.value -def config_set(config: Union[WrappedConfig[T], T], value: T, save_config=True): - if isinstance(config, WrappedConfig): - config.value = value - if save_config: - config.save() - else: - config = value +class AppConfig: + _state: dict[str, WrappedConfig] + def __init__(self): + super().__setattr__("_state", {}) -def config_get(config: Union[WrappedConfig[T], T]) -> T: - if isinstance(config, WrappedConfig): - return config.value - return config + def __setattr__(self, key, value): + if isinstance(value, WrappedConfig): + self._state[key] = value + else: + self._state[key].value = value + self._state[key].save() + + def __getattr__(self, key): + return self._state[key].value #################################### diff --git a/backend/main.py b/backend/main.py index 6f94a8dad..e2d7e18a3 100644 --- a/backend/main.py +++ b/backend/main.py @@ -58,8 +58,7 @@ from config import ( SRC_LOG_LEVELS, WEBHOOK_URL, ENABLE_ADMIN_EXPORT, - config_get, - config_set, + AppConfig, ) from constants import ERROR_MESSAGES @@ -96,10 +95,11 @@ https://github.com/open-webui/open-webui app = FastAPI(docs_url="/docs" if ENV == "dev" else None, redoc_url=None) -app.state.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER -app.state.MODEL_FILTER_LIST = MODEL_FILTER_LIST +app.state.config = AppConfig() +app.state.config.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER +app.state.config.MODEL_FILTER_LIST = MODEL_FILTER_LIST -app.state.WEBHOOK_URL = WEBHOOK_URL +app.state.config.WEBHOOK_URL = WEBHOOK_URL origins = ["*"] @@ -245,11 +245,9 @@ async def get_app_config(): "version": VERSION, "auth": WEBUI_AUTH, "default_locale": default_locale, - "images": config_get(images_app.state.ENABLED), - "default_models": config_get(webui_app.state.DEFAULT_MODELS), - "default_prompt_suggestions": config_get( - webui_app.state.DEFAULT_PROMPT_SUGGESTIONS - ), + "images": images_app.state.config.ENABLED, + "default_models": webui_app.state.config.DEFAULT_MODELS, + "default_prompt_suggestions": webui_app.state.config.DEFAULT_PROMPT_SUGGESTIONS, "trusted_header_auth": bool(webui_app.state.AUTH_TRUSTED_EMAIL_HEADER), "admin_export_enabled": ENABLE_ADMIN_EXPORT, } @@ -258,8 +256,8 @@ async def get_app_config(): @app.get("/api/config/model/filter") async def get_model_filter_config(user=Depends(get_admin_user)): return { - "enabled": config_get(app.state.ENABLE_MODEL_FILTER), - "models": config_get(app.state.MODEL_FILTER_LIST), + "enabled": app.state.config.ENABLE_MODEL_FILTER, + "models": app.state.config.MODEL_FILTER_LIST, } @@ -272,28 +270,28 @@ class ModelFilterConfigForm(BaseModel): async def update_model_filter_config( form_data: ModelFilterConfigForm, user=Depends(get_admin_user) ): - config_set(app.state.ENABLE_MODEL_FILTER, form_data.enabled) - config_set(app.state.MODEL_FILTER_LIST, form_data.models) + app.state.config.ENABLE_MODEL_FILTER, form_data.enabled + app.state.config.MODEL_FILTER_LIST, form_data.models - ollama_app.state.ENABLE_MODEL_FILTER = config_get(app.state.ENABLE_MODEL_FILTER) - ollama_app.state.MODEL_FILTER_LIST = config_get(app.state.MODEL_FILTER_LIST) + ollama_app.state.ENABLE_MODEL_FILTER = app.state.config.ENABLE_MODEL_FILTER + ollama_app.state.MODEL_FILTER_LIST = app.state.config.MODEL_FILTER_LIST - openai_app.state.ENABLE_MODEL_FILTER = config_get(app.state.ENABLE_MODEL_FILTER) - openai_app.state.MODEL_FILTER_LIST = config_get(app.state.MODEL_FILTER_LIST) + openai_app.state.ENABLE_MODEL_FILTER = app.state.config.ENABLE_MODEL_FILTER + openai_app.state.MODEL_FILTER_LIST = app.state.config.MODEL_FILTER_LIST - litellm_app.state.ENABLE_MODEL_FILTER = config_get(app.state.ENABLE_MODEL_FILTER) - litellm_app.state.MODEL_FILTER_LIST = config_get(app.state.MODEL_FILTER_LIST) + litellm_app.state.ENABLE_MODEL_FILTER = app.state.config.ENABLE_MODEL_FILTER + litellm_app.state.MODEL_FILTER_LIST = app.state.config.MODEL_FILTER_LIST return { - "enabled": config_get(app.state.ENABLE_MODEL_FILTER), - "models": config_get(app.state.MODEL_FILTER_LIST), + "enabled": app.state.config.ENABLE_MODEL_FILTER, + "models": app.state.config.MODEL_FILTER_LIST, } @app.get("/api/webhook") async def get_webhook_url(user=Depends(get_admin_user)): return { - "url": config_get(app.state.WEBHOOK_URL), + "url": app.state.config.WEBHOOK_URL, } @@ -303,12 +301,12 @@ class UrlForm(BaseModel): @app.post("/api/webhook") async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)): - config_set(app.state.WEBHOOK_URL, form_data.url) + app.state.config.WEBHOOK_URL = form_data.url - webui_app.state.WEBHOOK_URL = config_get(app.state.WEBHOOK_URL) + webui_app.state.WEBHOOK_URL = app.state.config.WEBHOOK_URL return { - "url": config_get(app.state.WEBHOOK_URL), + "url": app.state.config.WEBHOOK_URL, } From a0dceb06a5a3c31b9be8617179fe9c1876abc8ca Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Fri, 10 May 2024 15:20:22 +0800 Subject: [PATCH 08/29] fix: nested WrappedConfig breaks things --- backend/config.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/backend/config.py b/backend/config.py index 845a812ce..a619bb746 100644 --- a/backend/config.py +++ b/backend/config.py @@ -511,10 +511,8 @@ DEFAULT_USER_ROLE = WrappedConfig( os.getenv("DEFAULT_USER_ROLE", "pending"), ) -USER_PERMISSIONS_CHAT_DELETION = WrappedConfig( - "USER_PERMISSIONS_CHAT_DELETION", - "ui.user_permissions.chat.deletion", - os.environ.get("USER_PERMISSIONS_CHAT_DELETION", "True").lower() == "true", +USER_PERMISSIONS_CHAT_DELETION = ( + os.environ.get("USER_PERMISSIONS_CHAT_DELETION", "True").lower() == "true" ) USER_PERMISSIONS = WrappedConfig( From d2954f8eb6a85b2052773b69b2140340b1cd4897 Mon Sep 17 00:00:00 2001 From: Yanyutin753 <132346501+Yanyutin753@users.noreply.github.com> Date: Sat, 11 May 2024 09:33:31 +0800 Subject: [PATCH 09/29] feat format --- src/lib/i18n/locales/ar-BH/translation.json | 2 +- src/lib/i18n/locales/bg-BG/translation.json | 2 +- src/lib/i18n/locales/bn-BD/translation.json | 2 +- src/lib/i18n/locales/ca-ES/translation.json | 2 +- src/lib/i18n/locales/zh-CN/translation.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index bc8a5e358..8ffc3fae5 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -492,4 +492,4 @@ "You're now logged in.": "لقد قمت الآن بتسجيل الدخول.", "Youtube": "Youtube", "Youtube Loader Settings": "" -} \ No newline at end of file +} diff --git a/src/lib/i18n/locales/bg-BG/translation.json b/src/lib/i18n/locales/bg-BG/translation.json index 73fbb40d6..a9d374c4c 100644 --- a/src/lib/i18n/locales/bg-BG/translation.json +++ b/src/lib/i18n/locales/bg-BG/translation.json @@ -492,4 +492,4 @@ "You're now logged in.": "Сега, вие влязохте в системата.", "Youtube": "", "Youtube Loader Settings": "" -} \ No newline at end of file +} diff --git a/src/lib/i18n/locales/bn-BD/translation.json b/src/lib/i18n/locales/bn-BD/translation.json index 4a34a66d2..44ab2f5f2 100644 --- a/src/lib/i18n/locales/bn-BD/translation.json +++ b/src/lib/i18n/locales/bn-BD/translation.json @@ -492,4 +492,4 @@ "You're now logged in.": "আপনি এখন লগইন করা অবস্থায় আছেন", "Youtube": "", "Youtube Loader Settings": "" -} \ No newline at end of file +} diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index bd8201a45..81cd6eb58 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -492,4 +492,4 @@ "You're now logged in.": "Ara estàs connectat.", "Youtube": "", "Youtube Loader Settings": "" -} \ No newline at end of file +} diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index 91fab088d..53f359a0b 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -492,4 +492,4 @@ "You're now logged in.": "已登录。", "Youtube": "", "Youtube Loader Settings": "Youtube 加载器设置" -} \ No newline at end of file +} From 311382589568dc3d504095ec8c69086590a9fab0 Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Sat, 11 May 2024 16:34:04 +0800 Subject: [PATCH 10/29] feat: better handle openai errors, add error message to message --- src/lib/apis/streaming/index.ts | 7 + src/routes/(app)/+page.svelte | 306 ++++++++++++++------------- src/routes/(app)/c/[id]/+page.svelte | 305 +++++++++++++------------- 3 files changed, 330 insertions(+), 288 deletions(-) diff --git a/src/lib/apis/streaming/index.ts b/src/lib/apis/streaming/index.ts index 0e87c2524..bb1b55b1d 100644 --- a/src/lib/apis/streaming/index.ts +++ b/src/lib/apis/streaming/index.ts @@ -6,6 +6,8 @@ type TextStreamUpdate = { value: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any citations?: any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + error?: any; }; // createOpenAITextStream takes a responseBody with a SSE response, @@ -47,6 +49,11 @@ async function* openAIStreamToIterator( const parsedData = JSON.parse(data); console.log(parsedData); + if (parsedData.error) { + yield { done: true, value: '', error: parsedData.error }; + break; + } + if (parsedData.citations) { yield { done: false, value: '', citations: parsedData.citations }; continue; diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte index 47bdeb36b..378411a77 100644 --- a/src/routes/(app)/+page.svelte +++ b/src/routes/(app)/+page.svelte @@ -557,166 +557,146 @@ scrollToBottom(); - const [res, controller] = await generateOpenAIChatCompletion( - localStorage.token, - { - model: model.id, - stream: true, - messages: [ - $settings.system - ? { - role: 'system', - content: $settings.system - } - : undefined, - ...messages - ] - .filter((message) => message) - .map((message, idx, arr) => ({ - role: message.role, - ...((message.files?.filter((file) => file.type === 'image').length > 0 ?? false) && - message.role === 'user' + try { + const [res, controller] = await generateOpenAIChatCompletion( + localStorage.token, + { + model: model.id, + stream: true, + messages: [ + $settings.system ? { - content: [ - { - type: 'text', - text: - arr.length - 1 !== idx - ? message.content - : message?.raContent ?? message.content - }, - ...message.files - .filter((file) => file.type === 'image') - .map((file) => ({ - type: 'image_url', - image_url: { - url: file.url - } - })) - ] + role: 'system', + content: $settings.system } - : { - content: - arr.length - 1 !== idx ? message.content : message?.raContent ?? message.content - }) - })), - seed: $settings?.options?.seed ?? undefined, - stop: - $settings?.options?.stop ?? undefined - ? $settings?.options?.stop.map((str) => - decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"')) - ) - : undefined, - temperature: $settings?.options?.temperature ?? undefined, - top_p: $settings?.options?.top_p ?? undefined, - num_ctx: $settings?.options?.num_ctx ?? undefined, - frequency_penalty: $settings?.options?.repeat_penalty ?? undefined, - max_tokens: $settings?.options?.num_predict ?? undefined, - docs: docs.length > 0 ? docs : undefined, - citations: docs.length > 0 - }, - model?.source?.toLowerCase() === 'litellm' - ? `${LITELLM_API_BASE_URL}/v1` - : `${OPENAI_API_BASE_URL}` - ); + : undefined, + ...messages + ] + .filter((message) => message) + .map((message, idx, arr) => ({ + role: message.role, + ...((message.files?.filter((file) => file.type === 'image').length > 0 ?? false) && + message.role === 'user' + ? { + content: [ + { + type: 'text', + text: + arr.length - 1 !== idx + ? message.content + : message?.raContent ?? message.content + }, + ...message.files + .filter((file) => file.type === 'image') + .map((file) => ({ + type: 'image_url', + image_url: { + url: file.url + } + })) + ] + } + : { + content: + arr.length - 1 !== idx + ? message.content + : message?.raContent ?? message.content + }) + })), + seed: $settings?.options?.seed ?? undefined, + stop: + $settings?.options?.stop ?? undefined + ? $settings.options.stop.map((str) => + decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"')) + ) + : undefined, + temperature: $settings?.options?.temperature ?? undefined, + top_p: $settings?.options?.top_p ?? undefined, + num_ctx: $settings?.options?.num_ctx ?? undefined, + frequency_penalty: $settings?.options?.repeat_penalty ?? undefined, + max_tokens: $settings?.options?.num_predict ?? undefined, + docs: docs.length > 0 ? docs : undefined, + citations: docs.length > 0 + }, + model?.source?.toLowerCase() === 'litellm' + ? `${LITELLM_API_BASE_URL}/v1` + : `${OPENAI_API_BASE_URL}` + ); - // Wait until history/message have been updated - await tick(); + // Wait until history/message have been updated + await tick(); - scrollToBottom(); + scrollToBottom(); - if (res && res.ok && res.body) { - const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks); + if (res && res.ok && res.body) { + const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks); - for await (const update of textStream) { - const { value, done, citations } = update; - if (done || stopResponseFlag || _chatId !== $chatId) { - responseMessage.done = true; - messages = messages; + for await (const update of textStream) { + const { value, done, citations, error } = update; + if (error) { + await handleOpenAIError(error, null, model, responseMessage); + break; + } + if (done || stopResponseFlag || _chatId !== $chatId) { + responseMessage.done = true; + messages = messages; - if (stopResponseFlag) { - controller.abort('User: Stop Response'); + if (stopResponseFlag) { + controller.abort('User: Stop Response'); + } + + break; } - break; - } + if (citations) { + responseMessage.citations = citations; + continue; + } - if (citations) { - responseMessage.citations = citations; - continue; - } - - if (responseMessage.content == '' && value == '\n') { - continue; - } else { - responseMessage.content += value; - messages = messages; - } - - if ($settings.notificationEnabled && !document.hasFocus()) { - const notification = new Notification(`OpenAI ${model}`, { - body: responseMessage.content, - icon: `${WEBUI_BASE_URL}/static/favicon.png` - }); - } - - if ($settings.responseAutoCopy) { - copyToClipboard(responseMessage.content); - } - - if ($settings.responseAutoPlayback) { - await tick(); - document.getElementById(`speak-button-${responseMessage.id}`)?.click(); - } - - if (autoScroll) { - scrollToBottom(); - } - } - - if ($chatId == _chatId) { - if ($settings.saveChatHistory ?? true) { - chat = await updateChatById(localStorage.token, _chatId, { - messages: messages, - history: history - }); - await chats.set(await getChatList(localStorage.token)); - } - } - } else { - if (res !== null) { - const error = await res.json(); - console.log(error); - if ('detail' in error) { - toast.error(error.detail); - responseMessage.content = error.detail; - } else { - if ('message' in error.error) { - toast.error(error.error.message); - responseMessage.content = error.error.message; + if (responseMessage.content == '' && value == '\n') { + continue; } else { - toast.error(error.error); - responseMessage.content = error.error; + responseMessage.content += value; + messages = messages; + } + + if ($settings.notificationEnabled && !document.hasFocus()) { + const notification = new Notification(`OpenAI ${model}`, { + body: responseMessage.content, + icon: `${WEBUI_BASE_URL}/static/favicon.png` + }); + } + + if ($settings.responseAutoCopy) { + copyToClipboard(responseMessage.content); + } + + if ($settings.responseAutoPlayback) { + await tick(); + document.getElementById(`speak-button-${responseMessage.id}`)?.click(); + } + + if (autoScroll) { + scrollToBottom(); + } + } + + if ($chatId == _chatId) { + if ($settings.saveChatHistory ?? true) { + chat = await updateChatById(localStorage.token, _chatId, { + messages: messages, + history: history + }); + await chats.set(await getChatList(localStorage.token)); } } } else { - toast.error( - $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { - provider: model.name ?? model.id - }) - ); - responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { - provider: model.name ?? model.id - }); + await handleOpenAIError(null, res, model, responseMessage); } - - responseMessage.error = true; - responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { - provider: model.name ?? model.id - }); - responseMessage.done = true; - messages = messages; + } catch (error) { + await handleOpenAIError(error, null, model, responseMessage); } + messages = messages; stopResponseFlag = false; await tick(); @@ -733,6 +713,44 @@ } }; + const handleOpenAIError = async (error, res: Response | null, model, responseMessage) => { + let errorMessage = ''; + let innerError; + + if (error) { + innerError = error; + } else if (res !== null) { + innerError = await res.json(); + } + console.error(innerError); + if ('detail' in innerError) { + toast.error(innerError.detail); + errorMessage = innerError.detail; + } else if ('error' in innerError) { + if ('message' in innerError.error) { + toast.error(innerError.error.message); + errorMessage = innerError.error.message; + } else { + toast.error(innerError.error); + errorMessage = innerError.error; + } + } else if ('message' in innerError) { + toast.error(innerError.message); + errorMessage = innerError.message; + } + + responseMessage.error = true; + responseMessage.content = + $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { + provider: model.name ?? model.id + }) + + '\n' + + errorMessage; + responseMessage.done = true; + + messages = messages; + }; + const stopResponse = () => { stopResponseFlag = true; console.log('stopResponse'); diff --git a/src/routes/(app)/c/[id]/+page.svelte b/src/routes/(app)/c/[id]/+page.svelte index ccf85317e..117cbd9e1 100644 --- a/src/routes/(app)/c/[id]/+page.svelte +++ b/src/routes/(app)/c/[id]/+page.svelte @@ -561,165 +561,144 @@ scrollToBottom(); - const [res, controller] = await generateOpenAIChatCompletion( - localStorage.token, - { - model: model.id, - stream: true, - messages: [ - $settings.system - ? { - role: 'system', - content: $settings.system - } - : undefined, - ...messages - ] - .filter((message) => message) - .map((message, idx, arr) => ({ - role: message.role, - ...((message.files?.filter((file) => file.type === 'image').length > 0 ?? false) && - message.role === 'user' + try { + const [res, controller] = await generateOpenAIChatCompletion( + localStorage.token, + { + model: model.id, + stream: true, + messages: [ + $settings.system ? { - content: [ - { - type: 'text', - text: - arr.length - 1 !== idx - ? message.content - : message?.raContent ?? message.content - }, - ...message.files - .filter((file) => file.type === 'image') - .map((file) => ({ - type: 'image_url', - image_url: { - url: file.url - } - })) - ] + role: 'system', + content: $settings.system } - : { - content: - arr.length - 1 !== idx ? message.content : message?.raContent ?? message.content - }) - })), - seed: $settings?.options?.seed ?? undefined, - stop: - $settings?.options?.stop ?? undefined - ? $settings.options.stop.map((str) => - decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"')) - ) - : undefined, - temperature: $settings?.options?.temperature ?? undefined, - top_p: $settings?.options?.top_p ?? undefined, - num_ctx: $settings?.options?.num_ctx ?? undefined, - frequency_penalty: $settings?.options?.repeat_penalty ?? undefined, - max_tokens: $settings?.options?.num_predict ?? undefined, - docs: docs.length > 0 ? docs : undefined, - citations: docs.length > 0 - }, - model?.source?.toLowerCase() === 'litellm' - ? `${LITELLM_API_BASE_URL}/v1` - : `${OPENAI_API_BASE_URL}` - ); + : undefined, + ...messages + ] + .filter((message) => message) + .map((message, idx, arr) => ({ + role: message.role, + ...((message.files?.filter((file) => file.type === 'image').length > 0 ?? false) && + message.role === 'user' + ? { + content: [ + { + type: 'text', + text: + arr.length - 1 !== idx + ? message.content + : message?.raContent ?? message.content + }, + ...message.files + .filter((file) => file.type === 'image') + .map((file) => ({ + type: 'image_url', + image_url: { + url: file.url + } + })) + ] + } + : { + content: + arr.length - 1 !== idx + ? message.content + : message?.raContent ?? message.content + }) + })), + seed: $settings?.options?.seed ?? undefined, + stop: + $settings?.options?.stop ?? undefined + ? $settings.options.stop.map((str) => + decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"')) + ) + : undefined, + temperature: $settings?.options?.temperature ?? undefined, + top_p: $settings?.options?.top_p ?? undefined, + num_ctx: $settings?.options?.num_ctx ?? undefined, + frequency_penalty: $settings?.options?.repeat_penalty ?? undefined, + max_tokens: $settings?.options?.num_predict ?? undefined, + docs: docs.length > 0 ? docs : undefined, + citations: docs.length > 0 + }, + model?.source?.toLowerCase() === 'litellm' + ? `${LITELLM_API_BASE_URL}/v1` + : `${OPENAI_API_BASE_URL}` + ); - // Wait until history/message have been updated - await tick(); + // Wait until history/message have been updated + await tick(); - scrollToBottom(); + scrollToBottom(); - if (res && res.ok && res.body) { - const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks); + if (res && res.ok && res.body) { + const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks); - for await (const update of textStream) { - const { value, done, citations } = update; - if (done || stopResponseFlag || _chatId !== $chatId) { - responseMessage.done = true; - messages = messages; + for await (const update of textStream) { + const { value, done, citations, error } = update; + if (error) { + await handleOpenAIError(error, null, model, responseMessage); + break; + } + if (done || stopResponseFlag || _chatId !== $chatId) { + responseMessage.done = true; + messages = messages; - if (stopResponseFlag) { - controller.abort('User: Stop Response'); + if (stopResponseFlag) { + controller.abort('User: Stop Response'); + } + + break; } - break; - } + if (citations) { + responseMessage.citations = citations; + continue; + } - if (citations) { - responseMessage.citations = citations; - continue; - } - - if (responseMessage.content == '' && value == '\n') { - continue; - } else { - responseMessage.content += value; - messages = messages; - } - - if ($settings.notificationEnabled && !document.hasFocus()) { - const notification = new Notification(`OpenAI ${model}`, { - body: responseMessage.content, - icon: `${WEBUI_BASE_URL}/static/favicon.png` - }); - } - - if ($settings.responseAutoCopy) { - copyToClipboard(responseMessage.content); - } - - if ($settings.responseAutoPlayback) { - await tick(); - document.getElementById(`speak-button-${responseMessage.id}`)?.click(); - } - - if (autoScroll) { - scrollToBottom(); - } - } - - if ($chatId == _chatId) { - if ($settings.saveChatHistory ?? true) { - chat = await updateChatById(localStorage.token, _chatId, { - messages: messages, - history: history - }); - await chats.set(await getChatList(localStorage.token)); - } - } - } else { - if (res !== null) { - const error = await res.json(); - console.log(error); - if ('detail' in error) { - toast.error(error.detail); - responseMessage.content = error.detail; - } else { - if ('message' in error.error) { - toast.error(error.error.message); - responseMessage.content = error.error.message; + if (responseMessage.content == '' && value == '\n') { + continue; } else { - toast.error(error.error); - responseMessage.content = error.error; + responseMessage.content += value; + messages = messages; + } + + if ($settings.notificationEnabled && !document.hasFocus()) { + const notification = new Notification(`OpenAI ${model}`, { + body: responseMessage.content, + icon: `${WEBUI_BASE_URL}/static/favicon.png` + }); + } + + if ($settings.responseAutoCopy) { + copyToClipboard(responseMessage.content); + } + + if ($settings.responseAutoPlayback) { + await tick(); + document.getElementById(`speak-button-${responseMessage.id}`)?.click(); + } + + if (autoScroll) { + scrollToBottom(); + } + } + + if ($chatId == _chatId) { + if ($settings.saveChatHistory ?? true) { + chat = await updateChatById(localStorage.token, _chatId, { + messages: messages, + history: history + }); + await chats.set(await getChatList(localStorage.token)); } } } else { - toast.error( - $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { - provider: model.name ?? model.id - }) - ); - responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { - provider: model.name ?? model.id - }); + await handleOpenAIError(null, res, model, responseMessage); } - - responseMessage.error = true; - responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { - provider: model.name ?? model.id - }); - responseMessage.done = true; - messages = messages; + } catch (error) { + await handleOpenAIError(error, null, model, responseMessage); } stopResponseFlag = false; @@ -737,6 +716,44 @@ } }; + const handleOpenAIError = async (error, res: Response | null, model, responseMessage) => { + let errorMessage = ''; + let innerError; + + if (error) { + innerError = error; + } else if (res !== null) { + innerError = await res.json(); + } + console.error(innerError); + if ('detail' in innerError) { + toast.error(innerError.detail); + errorMessage = innerError.detail; + } else if ('error' in innerError) { + if ('message' in innerError.error) { + toast.error(innerError.error.message); + errorMessage = innerError.error.message; + } else { + toast.error(innerError.error); + errorMessage = innerError.error; + } + } else if ('message' in innerError) { + toast.error(innerError.message); + errorMessage = innerError.message; + } + + responseMessage.error = true; + responseMessage.content = + $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { + provider: model.name ?? model.id + }) + + '\n' + + errorMessage; + responseMessage.done = true; + + messages = messages; + }; + const stopResponse = () => { stopResponseFlag = true; console.log('stopResponse'); From e3e037e187e4f73a243d04e533eed693fc10abde Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Sat, 11 May 2024 17:43:53 +0800 Subject: [PATCH 11/29] fix: windows invocations of prettier --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f8096269c..d717ec7fe 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,9 @@ "lint:frontend": "eslint . --fix", "lint:types": "npm run check", "lint:backend": "pylint backend/", - "format": "prettier --plugin-search-dir --write '**/*.{js,ts,svelte,css,md,html,json}'", + "format": "prettier --plugin-search-dir --write \"**/*.{js,ts,svelte,css,md,html,json}\"", "format:backend": "black . --exclude \"/venv/\"", - "i18n:parse": "i18next --config i18next-parser.config.ts && prettier --write 'src/lib/i18n/**/*.{js,json}'", + "i18n:parse": "i18next --config i18next-parser.config.ts && prettier --write \"src/lib/i18n/**/*.{js,json}\"", "cy:open": "cypress open" }, "devDependencies": { From 55060045da6e8fbe5a9d161734a35e410cada946 Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Sat, 11 May 2024 17:44:04 +0800 Subject: [PATCH 12/29] feat: add .gitignore to .prettierignore --- .prettierignore | 308 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 302 insertions(+), 6 deletions(-) diff --git a/.prettierignore b/.prettierignore index b722147c4..bdcce08cc 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,11 @@ +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock + +kubernetes/ + +# Copy of .gitignore .DS_Store node_modules /build @@ -6,11 +14,299 @@ node_modules .env .env.* !.env.example +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class -# Ignore files for PNPM, NPM and YARN -pnpm-lock.yaml -package-lock.json -yarn.lock +# C extensions +*.so -# Ignore kubernetes files -kubernetes \ No newline at end of file +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# cypress artifacts +cypress/videos +cypress/screenshots From 3a4f3e97e77d8b695a3d2e569b6b1bdb4c5d7962 Mon Sep 17 00:00:00 2001 From: bulek Date: Sat, 11 May 2024 21:31:31 +0200 Subject: [PATCH 13/29] Added missing translations and corrected some spelling errors --- src/lib/i18n/locales/pl-PL/translation.json | 280 ++++++++++---------- 1 file changed, 140 insertions(+), 140 deletions(-) diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index cefa2f03c..11ad380df 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -4,31 +4,31 @@ "(e.g. `sh webui.sh --api`)": "(np. `sh webui.sh --api`)", "(latest)": "(najnowszy)", "{{modelName}} is thinking...": "{{modelName}} myśli...", - "{{user}}'s Chats": "", + "{{user}}'s Chats": "{{user}} - czaty", "{{webUIName}} Backend Required": "Backend {{webUIName}} wymagane", "a user": "użytkownik", "About": "O nas", "Account": "Konto", - "Accurate information": "", + "Accurate information": "Dokładna informacja", "Add a model": "Dodaj model", "Add a model tag name": "Dodaj nazwę tagu modelu", "Add a short description about what this modelfile does": "Dodaj krótki opis tego, co robi ten plik modelu", "Add a short title for this prompt": "Dodaj krótki tytuł tego polecenia", "Add a tag": "Dodaj tag", - "Add custom prompt": "", + "Add custom prompt": "Dodaj własne polecenie", "Add Docs": "Dodaj dokumenty", "Add Files": "Dodaj pliki", "Add message": "Dodaj wiadomość", - "Add Model": "", - "Add Tags": "dodaj tagi", - "Add User": "", + "Add Model": "Dodaj model", + "Add Tags": "Dodaj tagi", + "Add User": "Dodaj użytkownika", "Adjusting these settings will apply changes universally to all users.": "Dostosowanie tych ustawień spowoduje zastosowanie zmian uniwersalnie do wszystkich użytkowników.", "admin": "admin", "Admin Panel": "Panel administracyjny", "Admin Settings": "Ustawienia administratora", "Advanced Parameters": "Zaawansowane parametry", "all": "wszyscy", - "All Documents": "", + "All Documents": "Wszystkie dokumenty", "All Users": "Wszyscy użytkownicy", "Allow": "Pozwól", "Allow Chat Deletion": "Pozwól na usuwanie czatu", @@ -36,32 +36,32 @@ "Already have an account?": "Masz już konto?", "an assistant": "asystent", "and": "i", - "and create a new shared link.": "", + "and create a new shared link.": "i utwórz nowy udostępniony link", "API Base URL": "Podstawowy adres URL interfejsu API", "API Key": "Klucz API", - "API Key created.": "", - "API keys": "", + "API Key created.": "Klucz API utworzony.", + "API keys": "Klucze API", "API RPM": "Pakiet API RPM", - "April": "", - "Archive": "", - "Archived Chats": "", + "April": "Kwiecień", + "Archive": "Archiwum", + "Archived Chats": "Zarchiwizowane czaty", "are allowed - Activate this command by typing": "są dozwolone - Aktywuj to polecenie, wpisując", "Are you sure?": "Jesteś pewien?", - "Attach file": "", - "Attention to detail": "", + "Attach file": "Dołącz plik", + "Attention to detail": "Dbałość o szczegóły", "Audio": "Dźwięk", - "August": "", + "August": "Sierpień", "Auto-playback response": "Odtwarzanie automatyczne odpowiedzi", "Auto-send input after 3 sec.": "Wysyłanie automatyczne po 3 sek.", "AUTOMATIC1111 Base URL": "Podstawowy adres URL AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Podstawowy adres URL AUTOMATIC1111 jest wymagany.", "available!": "dostępny!", "Back": "Wstecz", - "Bad Response": "", - "before": "", - "Being lazy": "", + "Bad Response": "Zła odpowiedź", + "before": "przed", + "Being lazy": "Jest leniwy", "Builder Mode": "Tryb budowniczego", - "Bypass SSL verification for Websites": "", + "Bypass SSL verification for Websites": "Pomiń weryfikację SSL dla stron webowych", "Cancel": "Anuluj", "Categories": "Kategorie", "Change Password": "Zmień hasło", @@ -76,68 +76,68 @@ "Chunk Overlap": "Zachodzenie bloku", "Chunk Params": "Parametry bloku", "Chunk Size": "Rozmiar bloku", - "Citation": "", + "Citation": "Cytat", "Click here for help.": "Kliknij tutaj, aby uzyskać pomoc.", - "Click here to": "", + "Click here to": "Kliknij tutaj, żeby", "Click here to check other modelfiles.": "Kliknij tutaj, aby sprawdzić inne pliki modelowe.", "Click here to select": "Kliknij tutaj, aby wybrać", - "Click here to select a csv file.": "", + "Click here to select a csv file.": "Kliknij tutaj, żeby wybrać plik CSV", "Click here to select documents.": "Kliknij tutaj, aby wybrać dokumenty.", "click here.": "kliknij tutaj.", "Click on the user role button to change a user's role.": "Kliknij przycisk roli użytkownika, aby zmienić rolę użytkownika.", "Close": "Zamknij", "Collection": "Kolekcja", - "ComfyUI": "", - "ComfyUI Base URL": "", - "ComfyUI Base URL is required.": "", + "ComfyUI": "ComfyUI", + "ComfyUI Base URL": "Bazowy URL ComfyUI", + "ComfyUI Base URL is required.": "Bazowy URL ComfyUI jest wymagany.", "Command": "Polecenie", "Confirm Password": "Potwierdź hasło", "Connections": "Połączenia", "Content": "Zawartość", "Context Length": "Długość kontekstu", - "Continue Response": "", + "Continue Response": "Kontynuuj odpowiedź", "Conversation Mode": "Tryb rozmowy", - "Copied shared chat URL to clipboard!": "", - "Copy": "", + "Copied shared chat URL to clipboard!": "Skopiowano URL czatu do schowka!", + "Copy": "Kopiuj", "Copy last code block": "Skopiuj ostatni blok kodu", "Copy last response": "Skopiuj ostatnią odpowiedź", - "Copy Link": "", + "Copy Link": "Kopiuj link", "Copying to clipboard was successful!": "Kopiowanie do schowka zakończone powodzeniem!", "Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "Utwórz zwięzłą frazę składającą się z 3-5 słów jako nagłówek dla następującego zapytania, ściśle przestrzegając limitu od 3 do 5 słów i unikając użycia słowa 'tytuł':", "Create a modelfile": "Utwórz plik modelu", "Create Account": "Utwórz konto", - "Create new key": "", - "Create new secret key": "", + "Create new key": "Utwórz nowy klucz", + "Create new secret key": "Utwórz nowy klucz bezpieczeństwa", "Created at": "Utworzono o", - "Created At": "", + "Created At": "Utworzono o", "Current Model": "Bieżący model", "Current Password": "Bieżące hasło", "Custom": "Niestandardowy", "Customize Ollama models for a specific purpose": "Dostosuj modele Ollama do określonego celu", "Dark": "Ciemny", - "Dashboard": "", + "Dashboard": "Dashboard", "Database": "Baza danych", "DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm", - "December": "", + "December": "Grudzień", "Default": "Domyślny", "Default (Automatic1111)": "Domyślny (Automatic1111)", - "Default (SentenceTransformers)": "", - "Default (Web API)": "Domyślny (Interfejs API)", + "Default (SentenceTransformers)": "Domyślny (SentenceTransformers)", + "Default (Web API)": "Domyślny (Web API)", "Default model updated": "Domyślny model zaktualizowany", "Default Prompt Suggestions": "Domyślne sugestie promptów", "Default User Role": "Domyślna rola użytkownika", - "delete": "Usuń", - "Delete": "", + "delete": "usuń", + "Delete": "Usuń", "Delete a model": "Usuń model", "Delete chat": "Usuń czat", - "Delete Chat": "", + "Delete Chat": "Usuń czat", "Delete Chats": "Usuń czaty", - "delete this link": "", - "Delete User": "", + "delete this link": "usuń ten link", + "Delete User": "Usuń użytkownika", "Deleted {{deleteModelTag}}": "Usunięto {{deleteModelTag}}", - "Deleted {{tagName}}": "", + "Deleted {{tagName}}": "Usunięto {{tagName}}", "Description": "Opis", - "Didn't fully follow instructions": "", + "Didn't fully follow instructions": "Nie postępował zgodnie z instrukcjami", "Disabled": "Wyłączone", "Discover a modelfile": "Odkryj plik modelu", "Discover a prompt": "Odkryj prompt", @@ -150,28 +150,28 @@ "does not make any external connections, and your data stays securely on your locally hosted server.": "nie nawiązuje żadnych zewnętrznych połączeń, a Twoje dane pozostają bezpiecznie na Twoim lokalnie hostowanym serwerze.", "Don't Allow": "Nie zezwalaj", "Don't have an account?": "Nie masz konta?", - "Don't like the style": "", - "Download": "", - "Download canceled": "", + "Don't like the style": "Nie podobał mi się styl", + "Download": "Pobieranie", + "Download canceled": "Pobieranie przerwane", "Download Database": "Pobierz bazę danych", "Drop any files here to add to the conversation": "Upuść pliki tutaj, aby dodać do rozmowy", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "np. '30s', '10m'. Poprawne jednostki czasu to 's', 'm', 'h'.", - "Edit": "", + "Edit": "Edytuj", "Edit Doc": "Edytuj dokument", "Edit User": "Edytuj użytkownika", "Email": "Email", - "Embedding Model": "", - "Embedding Model Engine": "", - "Embedding model set to \"{{embedding_model}}\"": "", + "Embedding Model": "Model osadzania", + "Embedding Model Engine": "Silnik modelu osadzania", + "Embedding model set to \"{{embedding_model}}\"": "Model osadzania ustawiono na \"{{embedding_model}}\"", "Enable Chat History": "Włącz historię czatu", "Enable New Sign Ups": "Włącz nowe rejestracje", "Enabled": "Włączone", - "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "", + "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Upewnij się, że twój plik CSV zawiera 4 kolumny w następującym porządku: Nazwa, Email, Hasło, Rola.", "Enter {{role}} message here": "Wprowadź wiadomość {{role}} tutaj", "Enter Chunk Overlap": "Wprowadź zakchodzenie bloku", "Enter Chunk Size": "Wprowadź rozmiar bloku", "Enter Image Size (e.g. 512x512)": "Wprowadź rozmiar obrazu (np. 512x512)", - "Enter language codes": "", + "Enter language codes": "Wprowadź kody języków", "Enter LiteLLM API Base URL (litellm_params.api_base)": "Wprowadź bazowy adres URL LiteLLM API (litellm_params.api_base)", "Enter LiteLLM API Key (litellm_params.api_key)": "Wprowadź klucz API LiteLLM (litellm_params.api_key)", "Enter LiteLLM API RPM (litellm_params.rpm)": "Wprowadź API LiteLLM RPM(litellm_params.rpm)", @@ -179,68 +179,68 @@ "Enter Max Tokens (litellm_params.max_tokens)": "Wprowadź maksymalną liczbę tokenów (litellm_params.max_tokens)", "Enter model tag (e.g. {{modelTag}})": "Wprowadź tag modelu (np. {{modelTag}})", "Enter Number of Steps (e.g. 50)": "Wprowadź liczbę kroków (np. 50)", - "Enter Score": "", + "Enter Score": "Wprowadź wynik", "Enter stop sequence": "Wprowadź sekwencję zatrzymania", "Enter Top K": "Wprowadź Top K", "Enter URL (e.g. http://127.0.0.1:7860/)": "Wprowadź adres URL (np. http://127.0.0.1:7860/)", - "Enter URL (e.g. http://localhost:11434)": "", + "Enter URL (e.g. http://localhost:11434)": "Wprowadź adres URL (np. http://localhost:11434/)", "Enter Your Email": "Wprowadź swój adres email", "Enter Your Full Name": "Wprowadź swoje imię i nazwisko", "Enter Your Password": "Wprowadź swoje hasło", - "Enter Your Role": "", + "Enter Your Role": "Wprowadź swoją rolę", "Experimental": "Eksperymentalne", "Export All Chats (All Users)": "Eksportuj wszystkie czaty (wszyscy użytkownicy)", "Export Chats": "Eksportuj czaty", "Export Documents Mapping": "Eksportuj mapowanie dokumentów", "Export Modelfiles": "Eksportuj pliki modeli", "Export Prompts": "Eksportuj prompty", - "Failed to create API Key.": "", + "Failed to create API Key.": "Nie udało się utworzyć klucza API.", "Failed to read clipboard contents": "Nie udało się odczytać zawartości schowka", - "February": "", - "Feel free to add specific details": "", + "February": "Luty", + "Feel free to add specific details": "Podaj inne szczegóły", "File Mode": "Tryb pliku", "File not found.": "Plik nie został znaleziony.", "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Wykryto podszywanie się pod odcisk palca: Nie można używać inicjałów jako awatara. Przechodzenie do domyślnego obrazu profilowego.", "Fluidly stream large external response chunks": "Płynnie przesyłaj strumieniowo duże fragmenty odpowiedzi zewnętrznych", "Focus chat input": "Skoncentruj na czacie", - "Followed instructions perfectly": "", + "Followed instructions perfectly": "Postępował z idealnie według instrukcji", "Format your variables using square brackets like this:": "Formatuj swoje zmienne, używając nawiasów kwadratowych, np.", "From (Base Model)": "Z (Model Podstawowy)", "Full Screen Mode": "Tryb pełnoekranowy", "General": "Ogólne", "General Settings": "Ogólne ustawienia", - "Generation Info": "", - "Good Response": "", - "has no conversations.": "", + "Generation Info": "Informacja o generacji", + "Good Response": "Dobra odpowiedź", + "has no conversations.": "nie ma rozmów.", "Hello, {{name}}": "Witaj, {{name}}", - "Help": "", + "Help": "Pomoc", "Hide": "Ukryj", "Hide Additional Params": "Ukryj dodatkowe parametry", "How can I help you today?": "Jak mogę Ci dzisiaj pomóc?", - "Hybrid Search": "", + "Hybrid Search": "Szukanie hybrydowe", "Image Generation (Experimental)": "Generowanie obrazu (eksperymentalne)", "Image Generation Engine": "Silnik generowania obrazu", "Image Settings": "Ustawienia obrazu", "Images": "Obrazy", - "Import Chats": "Importuj rozmowy", + "Import Chats": "Importuj czaty", "Import Documents Mapping": "Importuj mapowanie dokumentów", "Import Modelfiles": "Importuj pliki modeli", "Import Prompts": "Importuj prompty", "Include `--api` flag when running stable-diffusion-webui": "Dołącz flagę `--api` podczas uruchamiania stable-diffusion-webui", - "Input commands": "", + "Input commands": "Wprowadź komendy", "Interface": "Interfejs", - "Invalid Tag": "", - "January": "", + "Invalid Tag": "Nieprawidłowy tag", + "January": "Styczeń", "join our Discord for help.": "Dołącz do naszego Discorda po pomoc.", "JSON": "JSON", - "July": "", - "June": "", + "July": "Lipiec", + "June": "Czerwiec", "JWT Expiration": "Wygaśnięcie JWT", "JWT Token": "Token JWT", "Keep Alive": "Zachowaj łączność", "Keyboard shortcuts": "Skróty klawiszowe", "Language": "Język", - "Last Active": "", + "Last Active": "Ostatnio aktywny", "Light": "Jasny", "Listening...": "Nasłuchiwanie...", "LLMs can make mistakes. Verify important information.": "LLMy mogą popełniać błędy. Zweryfikuj ważne informacje.", @@ -249,17 +249,17 @@ "Manage LiteLLM Models": "Zarządzaj modelami LiteLLM", "Manage Models": "Zarządzaj modelami", "Manage Ollama Models": "Zarządzaj modelami Ollama", - "March": "", + "March": "Marzec", "Max Tokens": "Maksymalna liczba tokenów", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksymalnie 3 modele można pobierać jednocześnie. Spróbuj ponownie później.", - "May": "", - "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "", - "Minimum Score": "", + "May": "Maj", + "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "WIadomości, które wyślesz po utworzeniu linku nie będą udostępnione. Użytkownicy z URL-em będą mogli zobaczyć udostępniony czat.", + "Minimum Score": "Minimalny wynik", "Mirostat": "Mirostat", "Mirostat Eta": "Mirostat Eta", "Mirostat Tau": "Mirostat Tau", "MMMM DD, YYYY": "MMMM DD, YYYY", - "MMMM DD, YYYY HH:mm": "", + "MMMM DD, YYYY HH:mm": "MMMM DD, YYYY HH:mm", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' został pomyślnie pobrany.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' jest już w kolejce do pobrania.", "Model {{modelId}} not found": "Model {{modelId}} nie został znaleziony", @@ -275,7 +275,7 @@ "Modelfile Content": "Zawartość pliku modelu", "Modelfiles": "Pliki modeli", "Models": "Modele", - "More": "", + "More": "Więcej", "My Documents": "Moje dokumenty", "My Modelfiles": "Moje pliki modeli", "My Prompts": "Moje prompty", @@ -284,19 +284,19 @@ "Name your modelfile": "Nadaj nazwę swojemu plikowi modelu", "New Chat": "Nowy czat", "New Password": "Nowe hasło", - "No results found": "", - "No source available": "", - "Not factually correct": "", + "No results found": "Nie znaleziono rezultatów", + "No source available": "Źródło nie dostępne", + "Not factually correct": "Nie zgodne z faktami", "Not sure what to add?": "Nie wiesz, co dodać?", "Not sure what to write? Switch to": "Nie wiesz, co napisać? Przełącz się na", - "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "", + "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Uwaga: Jeśli ustawisz minimalny wynik, szukanie zwróci jedynie dokumenty z wynikiem większym lub równym minimalnemu.", "Notifications": "Powiadomienia", - "November": "", - "October": "", + "November": "Listopad", + "October": "Październik", "Off": "Wyłączony", "Okay, Let's Go!": "Okej, zaczynamy!", - "OLED Dark": "", - "Ollama": "", + "OLED Dark": "Ciemny OLED", + "Ollama": "Ollama", "Ollama Base URL": "Adres bazowy URL Ollama", "Ollama Version": "Wersja Ollama", "On": "Włączony", @@ -304,57 +304,57 @@ "Only alphanumeric characters and hyphens are allowed in the command string.": "W poleceniu dozwolone są tylko znaki alfanumeryczne i myślniki.", "Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "Ups! Trzymaj się! Twoje pliki są wciąż w procesie obróbki. Gotujemy je do perfekcji. Prosimy o cierpliwość, poinformujemy Cię, gdy będą gotowe.", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! Wygląda na to, że URL jest nieprawidłowy. Sprawdź jeszcze raz i spróbuj ponownie.", - "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Używasz nieobsługiwaniej metody (tylko interfejs front-end). Proszę obsłużyć interfejs WebUI z poziomu backendu.", + "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Używasz nieobsługiwanej metody (tylko interfejs front-end). Proszę obsłużyć interfejs WebUI z poziomu backendu.", "Open": "Otwórz", "Open AI": "Open AI", "Open AI (Dall-E)": "Open AI (Dall-E)", "Open new chat": "Otwórz nowy czat", - "OpenAI": "", + "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", - "OpenAI API Config": "", + "OpenAI API Config": "Konfiguracja OpenAI API", "OpenAI API Key is required.": "Klucz API OpenAI jest wymagany.", - "OpenAI URL/Key required.": "", + "OpenAI URL/Key required.": "URL/Klucz OpenAI jest wymagany.", "or": "lub", - "Other": "", - "Overview": "", + "Other": "Inne", + "Overview": "Przegląd", "Parameters": "Parametry", "Password": "Hasło", - "PDF document (.pdf)": "", + "PDF document (.pdf)": "Dokument PDF (.pdf)", "PDF Extract Images (OCR)": "PDF Wyodrębnij obrazy (OCR)", "pending": "oczekujące", "Permission denied when accessing microphone: {{error}}": "Odmowa dostępu do mikrofonu: {{error}}", - "Plain text (.txt)": "", + "Plain text (.txt)": "Zwykły tekst (.txt)", "Playground": "Plac zabaw", - "Positive attitude": "", - "Previous 30 days": "", - "Previous 7 days": "", - "Profile Image": "", - "Prompt": "", - "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "", + "Positive attitude": "Pozytywne podejście", + "Previous 30 days": "Poprzednie 30 dni", + "Previous 7 days": "Poprzednie 7 dni", + "Profile Image": "Obrazek profilowy", + "Prompt": "Promopt", + "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Prompt (np. powiedz mi zabawny fakt o Imperium Rzymskim", "Prompt Content": "Zawartość prompta", "Prompt suggestions": "Sugestie prompta", "Prompts": "Prompty", - "Pull \"{{searchValue}}\" from Ollama.com": "", + "Pull \"{{searchValue}}\" from Ollama.com": "Pobierz \"{{searchValue}}\" z Ollama.com", "Pull a model from Ollama.com": "Pobierz model z Ollama.com", "Pull Progress": "Postęp pobierania", "Query Params": "Parametry zapytania", "RAG Template": "Szablon RAG", "Raw Format": "Format bez obróbki", - "Read Aloud": "", + "Read Aloud": "Czytaj na głos", "Record voice": "Nagraj głos", "Redirecting you to OpenWebUI Community": "Przekierowujemy Cię do społeczności OpenWebUI", - "Refused when it shouldn't have": "", - "Regenerate": "", + "Refused when it shouldn't have": "Odmówił, kiedy nie powinien", + "Regenerate": "Generuj ponownie", "Release Notes": "Notatki wydania", - "Remove": "", - "Remove Model": "", - "Rename": "", + "Remove": "Usuń", + "Remove Model": "Usuń model", + "Rename": "ZMień nazwę", "Repeat Last N": "Powtórz ostatnie N", "Repeat Penalty": "Kara za powtórzenie", "Request Mode": "Tryb żądania", - "Reranking Model": "", - "Reranking model disabled": "", - "Reranking model set to \"{{reranking_model}}\"": "", + "Reranking Model": "Zmiana rankingu modelu", + "Reranking model disabled": "Zmiana rankingu modelu zablokowana", + "Reranking model set to \"{{reranking_model}}\"": "Zmiana rankingu modelu ustawiona na \"{{reranking_model}}\"", "Reset Vector Storage": "Resetuj przechowywanie wektorów", "Response AutoCopy to Clipboard": "Automatyczne kopiowanie odpowiedzi do schowka", "Role": "Rola", @@ -369,7 +369,7 @@ "Scan complete!": "Skanowanie zakończone!", "Scan for documents from {{path}}": "Skanuj dokumenty z {{path}}", "Search": "Szukaj", - "Search a model": "", + "Search a model": "Szukaj modelu", "Search Documents": "Szukaj dokumentów", "Search Prompts": "Szukaj promptów", "See readme.md for instructions": "Zajrzyj do readme.md po instrukcje", @@ -378,73 +378,73 @@ "Select a mode": "Wybierz tryb", "Select a model": "Wybierz model", "Select an Ollama instance": "Wybierz instancję Ollama", - "Select model": "", + "Select model": "Wybierz model", "Send a Message": "Wyślij Wiadomość", "Send message": "Wyślij wiadomość", - "September": "", + "September": "Wrzesień", "Server connection verified": "Połączenie z serwerem zweryfikowane", "Set as default": "Ustaw jako domyślne", "Set Default Model": "Ustaw domyślny model", - "Set embedding model (e.g. {{model}})": "", + "Set embedding model (e.g. {{model}})": "Ustaw model osadzania (e.g. {{model}})", "Set Image Size": "Ustaw rozmiar obrazu", "Set Model": "Ustaw model", - "Set reranking model (e.g. {{model}})": "", + "Set reranking model (e.g. {{model}})": "Ustaw zmianę rankingu modelu (e.g. {{model}})", "Set Steps": "Ustaw kroki", "Set Title Auto-Generation Model": "Ustaw model automatycznego generowania tytułów", "Set Voice": "Ustaw głos", "Settings": "Ustawienia", "Settings saved successfully!": "Ustawienia zapisane pomyślnie!", - "Share": "", - "Share Chat": "", + "Share": "Udostępnij", + "Share Chat": "Udostępnij czat", "Share to OpenWebUI Community": "Dziel się z społecznością OpenWebUI", "short-summary": "Krótkie podsumowanie", "Show": "Pokaż", "Show Additional Params": "Pokaż dodatkowe parametry", "Show shortcuts": "Pokaż skróty", - "Showcased creativity": "", + "Showcased creativity": "Pokaz kreatywności", "sidebar": "Panel boczny", "Sign in": "Zaloguj się", "Sign Out": "Wyloguj się", "Sign up": "Zarejestruj się", - "Signing in": "", - "Source": "", + "Signing in": "Zalogowanie", + "Source": "Źródło", "Speech recognition error: {{error}}": "Błąd rozpoznawania mowy: {{error}}", "Speech-to-Text Engine": "Silnik mowy na tekst", "SpeechRecognition API is not supported in this browser.": "API Rozpoznawania Mowy nie jest obsługiwane w tej przeglądarce.", "Stop Sequence": "Zatrzymaj sekwencję", "STT Settings": "Ustawienia STT", "Submit": "Zatwierdź", - "Subtitle (e.g. about the Roman Empire)": "", + "Subtitle (e.g. about the Roman Empire)": "Podtytuł (np. o Imperium Rzymskim)", "Success": "Sukces", "Successfully updated.": "Pomyślnie zaktualizowano.", - "Suggested": "", + "Suggested": "Sugerowane", "Sync All": "Synchronizuj wszystko", "System": "System", "System Prompt": "Prompt systemowy", "Tags": "Tagi", - "Tell us more:": "", + "Tell us more:": "Powiedz nam więcej", "Temperature": "Temperatura", "Template": "Szablon", "Text Completion": "Uzupełnienie tekstu", "Text-to-Speech Engine": "Silnik tekstu na mowę", "Tfs Z": "Tfs Z", - "Thanks for your feedback!": "", - "The score should be a value between 0.0 (0%) and 1.0 (100%).": "", + "Thanks for your feedback!": "Dzięki za informację zwrotną!", + "The score should be a value between 0.0 (0%) and 1.0 (100%).": "Wynik powinien być wartością pomiędzy 0.0 (0%) a 1.0 (100%).", "Theme": "Motyw", "This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "To zapewnia, że Twoje cenne rozmowy są bezpiecznie zapisywane w bazie danych backendowej. Dziękujemy!", "This setting does not sync across browsers or devices.": "To ustawienie nie synchronizuje się między przeglądarkami ani urządzeniami.", - "Thorough explanation": "", + "Thorough explanation": "Dokładne wyjaśnienie", "Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "Porada: Aktualizuj wiele zmiennych kolejno, naciskając klawisz tabulatora w polu wprowadzania czatu po każdej zmianie.", "Title": "Tytuł", - "Title (e.g. Tell me a fun fact)": "", + "Title (e.g. Tell me a fun fact)": "Tytuł (np. Powiedz mi jakiś zabawny fakt)", "Title Auto-Generation": "Automatyczne generowanie tytułu", - "Title cannot be an empty string.": "", + "Title cannot be an empty string.": "Tytuł nie może być pusty", "Title Generation Prompt": "Prompt generowania tytułu", "to": "do", "To access the available model names for downloading,": "Aby uzyskać dostęp do dostępnych nazw modeli do pobrania,", "To access the GGUF models available for downloading,": "Aby uzyskać dostęp do dostępnych modeli GGUF do pobrania,", "to chat input.": "do pola wprowadzania czatu.", - "Today": "", + "Today": "Dzisiaj", "Toggle settings": "Przełącz ustawienia", "Toggle sidebar": "Przełącz panel boczny", "Top K": "Najlepsze K", @@ -454,7 +454,7 @@ "Type Hugging Face Resolve (Download) URL": "Wprowadź adres URL do pobrania z Hugging Face", "Uh-oh! There was an issue connecting to {{provider}}.": "O nie! Wystąpił problem z połączeniem z {{provider}}.", "Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Nieznany typ pliku '{{file_type}}', ale akceptowany i traktowany jako zwykły tekst", - "Update and Copy Link": "", + "Update and Copy Link": "Uaktualnij i skopiuj link", "Update password": "Aktualizacja hasła", "Upload a GGUF model": "Prześlij model GGUF", "Upload files": "Prześlij pliki", @@ -471,25 +471,25 @@ "variable": "zmienna", "variable to have them replaced with clipboard content.": "zmienna która zostanie zastąpiona zawartością schowka.", "Version": "Wersja", - "Warning: If you update or change your embedding model, you will need to re-import all documents.": "", + "Warning: If you update or change your embedding model, you will need to re-import all documents.": "Uwaga: Jeśli uaktualnisz lub zmienisz model osadzania, będziesz musiał ponownie zaimportować wszystkie dokumenty.", "Web": "Sieć", - "Web Loader Settings": "", - "Web Params": "", - "Webhook URL": "", + "Web Loader Settings": "Ustawienia pobierania z sieci", + "Web Params": "Parametry sieci", + "Webhook URL": "URL webhook", "WebUI Add-ons": "Dodatki do interfejsu WebUI", "WebUI Settings": "Ustawienia interfejsu WebUI", "WebUI will make requests to": "Interfejs sieciowy będzie wysyłał żądania do", "What’s New in": "Co nowego w", - "When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Kiedy historia jest wyłączona, nowe rozmowy na tej przeglądarce nie będą widoczne w historii na żadnym z twoich urządzeń.", + "When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Kiedy historia jest wyłączona, nowe czaty na tej przeglądarce nie będą widoczne w historii na żadnym z twoich urządzeń.", "Whisper (Local)": "Whisper (Lokalnie)", "Write a prompt suggestion (e.g. Who are you?)": "Napisz sugestię do polecenia (np. Kim jesteś?)", "Write a summary in 50 words that summarizes [topic or keyword].": "Napisz podsumowanie w 50 słowach, które podsumowuje [temat lub słowo kluczowe].", - "Yesterday": "", + "Yesterday": "Wczoraj", "You": "Ty", - "You have no archived conversations.": "", - "You have shared this chat": "", + "You have no archived conversations.": "Nie masz zarchiwizowanych rozmów.", + "You have shared this chat": "Udostępniłeś ten czat", "You're a helpful assistant.": "Jesteś pomocnym asystentem.", "You're now logged in.": "Jesteś teraz zalogowany.", - "Youtube": "", - "Youtube Loader Settings": "" + "Youtube": "Youtube", + "Youtube Loader Settings": "Ustawienia pobierania z Youtube" } From 4fa8d2aa5ab2a278fee019138d9147a638be1a5c Mon Sep 17 00:00:00 2001 From: Ethan <92686703+not-a-ethan@users.noreply.github.com> Date: Sun, 12 May 2024 01:33:49 +0000 Subject: [PATCH 14/29] Fixed link/formatting --- docs/CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index f78436d54..3e82c979c 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -17,7 +17,7 @@ If your issue or contribution pertains directly to the core Ollama technology, p ### 🚨 Reporting Issues -Noticed something off? Have an idea? Check our [Issues tab](https://github.com/open-webui/oopen-webui/issues) to see if it's already been reported or suggested. If not, feel free to open a new issue. When reporting an issue, please follow our issue templates. These templates are designed to ensure that all necessary details are provided from the start, enabling us to address your concerns more efficiently. +Noticed something off? Have an idea? Check our [Issues tab](https://github.com/open-webui/open-webui/issues) to see if it's already been reported or suggested. If not, feel free to open a new issue. When reporting an issue, please follow our issue templates. These templates are designed to ensure that all necessary details are provided from the start, enabling us to address your concerns more efficiently. > [!IMPORTANT] > @@ -54,7 +54,7 @@ Help us make Open WebUI more accessible by improving documentation, writing tuto Help us make Open WebUI available to a wider audience. In this section, we'll guide you through the process of adding new translations to the project. -We use JSON files to store translations. You can find the existing translation files in the `src/lib/i18n/locales` directory. Each directory corresponds to a specific language, for example, `en-US` for English (US), `fr-FR` for French (France) and so on. You can refer to [ISO 639 Language Codes][http://www.lingoes.net/en/translator/langcode.htm] to find the appropriate code for a specific language. +We use JSON files to store translations. You can find the existing translation files in the `src/lib/i18n/locales` directory. Each directory corresponds to a specific language, for example, `en-US` for English (US), `fr-FR` for French (France) and so on. You can refer to [ISO 639 Language Codes](http://www.lingoes.net/en/translator/langcode.htm) to find the appropriate code for a specific language. To add a new language: From 8e94db0d1b4c85671cc42d0b06dbc42e47cbad6b Mon Sep 17 00:00:00 2001 From: Silentoplayz <50341825+Silentoplayz@users.noreply.github.com> Date: Sun, 12 May 2024 02:38:40 +0000 Subject: [PATCH 15/29] Update pull_request_template.md Update Open WebUI pull request template to the latest version, striving to follow KeepaChangelog and Conventional Commits guidelines. --- .github/pull_request_template.md | 45 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 6eb861582..c4a3bb1fa 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,4 +1,4 @@ -## Pull Request Checklist +# Pull Request Checklist - [ ] **Target branch:** Pull requests should target the `dev` branch. - [ ] **Description:** Briefly describe the changes in this pull request. @@ -7,32 +7,46 @@ - [ ] **Dependencies:** Are there any new dependencies? Have you updated the dependency versions in the documentation? - [ ] **Testing:** Have you written and run sufficient tests for the changes? - [ ] **Code Review:** Have you self-reviewed your code and addressed any coding standard issues? +- [ ] **Label title:** Ensure the pull request title is labeled properly using one of the following: + - **BREAKING CHANGE**: Significant changes that may affect compatibility + - **build**: Changes that affect the build system or external dependencies + - **ci**: Changes to our continuous integration processes or workflows + - **chore**: Refactor, cleanup, or other non-functional code changes + - **docs**: Documentation update or addition + - **feat**: Introduces a new feature or enhancement to the codebase + - **fix**: Bug fix or error correction + - **i18n**: Internationalization or localization changes + - **perf**: Performance improvement + - **refactor**: Code restructuring for better maintainability, readability, or scalability + - **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc.) + - **test**: Adding missing tests or correcting existing tests + - **WIP**: Work in progress, a temporary label for incomplete or ongoing work ---- +# Changelog Entry -## Description +### Description -[Insert a brief description of the changes made in this pull request, including any relevant motivation and impact.] - ---- - -### Changelog Entry +- [Briefly describe the changes made in this pull request, including any relevant motivation and impact.] ### Added - [List any new features, functionalities, or additions] -### Fixed - -- [List any fixes, corrections, or bug fixes] - ### Changed - [List any changes, updates, refactorings, or optimizations] +### Deprecated + +- [List any deprecated functionality or features that have been removed] + ### Removed -- [List any removed features, files, or deprecated functionalities] +- [List any removed features, files, or functionalities] + +### Fixed + +- [List any fixes, corrections, or bug fixes] ### Security @@ -40,12 +54,11 @@ ### Breaking Changes -- [List any breaking changes affecting compatibility or functionality] +- **BREAKING CHANGE**: [List any breaking changes affecting compatibility or functionality] --- ### Additional Information - [Insert any additional context, notes, or explanations for the changes] - -- [Reference any related issues, commits, or other relevant information] + - [Reference any related issues, commits, or other relevant information] From 5d64822c84030c2a2c0631ddfa68362cd55463fa Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Sun, 12 May 2024 13:28:40 +0800 Subject: [PATCH 16/29] refac: rename WrappedConfig to PersistedConfig --- backend/config.py | 88 +++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/backend/config.py b/backend/config.py index a619bb746..106044540 100644 --- a/backend/config.py +++ b/backend/config.py @@ -201,7 +201,7 @@ def get_config_value(config_path: str): T = TypeVar("T") -class WrappedConfig(Generic[T]): +class PersistedConfig(Generic[T]): def __init__(self, env_name: str, config_path: str, env_value: T): self.env_name = env_name self.config_path = config_path @@ -219,13 +219,13 @@ class WrappedConfig(Generic[T]): @property def __dict__(self): raise TypeError( - "WrappedConfig object cannot be converted to dict, use config_get or .value instead." + "PersistedConfig object cannot be converted to dict, use config_get or .value instead." ) def __getattribute__(self, item): if item == "__dict__": raise TypeError( - "WrappedConfig object cannot be converted to dict, use config_get or .value instead." + "PersistedConfig object cannot be converted to dict, use config_get or .value instead." ) return super().__getattribute__(item) @@ -247,13 +247,13 @@ class WrappedConfig(Generic[T]): class AppConfig: - _state: dict[str, WrappedConfig] + _state: dict[str, PersistedConfig] def __init__(self): super().__setattr__("_state", {}) def __setattr__(self, key, value): - if isinstance(value, WrappedConfig): + if isinstance(value, PersistedConfig): self._state[key] = value else: self._state[key].value = value @@ -271,7 +271,7 @@ WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true" WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get( "WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None ) -JWT_EXPIRES_IN = WrappedConfig( +JWT_EXPIRES_IN = PersistedConfig( "JWT_EXPIRES_IN", "auth.jwt_expiry", os.environ.get("JWT_EXPIRES_IN", "-1") ) @@ -409,7 +409,7 @@ OLLAMA_BASE_URLS = os.environ.get("OLLAMA_BASE_URLS", "") OLLAMA_BASE_URLS = OLLAMA_BASE_URLS if OLLAMA_BASE_URLS != "" else OLLAMA_BASE_URL OLLAMA_BASE_URLS = [url.strip() for url in OLLAMA_BASE_URLS.split(";")] -OLLAMA_BASE_URLS = WrappedConfig( +OLLAMA_BASE_URLS = PersistedConfig( "OLLAMA_BASE_URLS", "ollama.base_urls", OLLAMA_BASE_URLS ) @@ -428,7 +428,7 @@ OPENAI_API_KEYS = os.environ.get("OPENAI_API_KEYS", "") OPENAI_API_KEYS = OPENAI_API_KEYS if OPENAI_API_KEYS != "" else OPENAI_API_KEY OPENAI_API_KEYS = [url.strip() for url in OPENAI_API_KEYS.split(";")] -OPENAI_API_KEYS = WrappedConfig("OPENAI_API_KEYS", "openai.api_keys", OPENAI_API_KEYS) +OPENAI_API_KEYS = PersistedConfig("OPENAI_API_KEYS", "openai.api_keys", OPENAI_API_KEYS) OPENAI_API_BASE_URLS = os.environ.get("OPENAI_API_BASE_URLS", "") OPENAI_API_BASE_URLS = ( @@ -439,7 +439,7 @@ OPENAI_API_BASE_URLS = [ url.strip() if url != "" else "https://api.openai.com/v1" for url in OPENAI_API_BASE_URLS.split(";") ] -OPENAI_API_BASE_URLS = WrappedConfig( +OPENAI_API_BASE_URLS = PersistedConfig( "OPENAI_API_BASE_URLS", "openai.api_base_urls", OPENAI_API_BASE_URLS ) @@ -458,7 +458,7 @@ OPENAI_API_BASE_URL = "https://api.openai.com/v1" # WEBUI #################################### -ENABLE_SIGNUP = WrappedConfig( +ENABLE_SIGNUP = PersistedConfig( "ENABLE_SIGNUP", "ui.enable_signup", ( @@ -467,11 +467,11 @@ ENABLE_SIGNUP = WrappedConfig( else os.environ.get("ENABLE_SIGNUP", "True").lower() == "true" ), ) -DEFAULT_MODELS = WrappedConfig( +DEFAULT_MODELS = PersistedConfig( "DEFAULT_MODELS", "ui.default_models", os.environ.get("DEFAULT_MODELS", None) ) -DEFAULT_PROMPT_SUGGESTIONS = WrappedConfig( +DEFAULT_PROMPT_SUGGESTIONS = PersistedConfig( "DEFAULT_PROMPT_SUGGESTIONS", "ui.prompt_suggestions", [ @@ -505,7 +505,7 @@ DEFAULT_PROMPT_SUGGESTIONS = WrappedConfig( ], ) -DEFAULT_USER_ROLE = WrappedConfig( +DEFAULT_USER_ROLE = PersistedConfig( "DEFAULT_USER_ROLE", "ui.default_user_role", os.getenv("DEFAULT_USER_ROLE", "pending"), @@ -515,25 +515,25 @@ USER_PERMISSIONS_CHAT_DELETION = ( os.environ.get("USER_PERMISSIONS_CHAT_DELETION", "True").lower() == "true" ) -USER_PERMISSIONS = WrappedConfig( +USER_PERMISSIONS = PersistedConfig( "USER_PERMISSIONS", "ui.user_permissions", {"chat": {"deletion": USER_PERMISSIONS_CHAT_DELETION}}, ) -ENABLE_MODEL_FILTER = WrappedConfig( +ENABLE_MODEL_FILTER = PersistedConfig( "ENABLE_MODEL_FILTER", "model_filter.enable", os.environ.get("ENABLE_MODEL_FILTER", "False").lower() == "true", ) MODEL_FILTER_LIST = os.environ.get("MODEL_FILTER_LIST", "") -MODEL_FILTER_LIST = WrappedConfig( +MODEL_FILTER_LIST = PersistedConfig( "MODEL_FILTER_LIST", "model_filter.list", [model.strip() for model in MODEL_FILTER_LIST.split(";")], ) -WEBHOOK_URL = WrappedConfig( +WEBHOOK_URL = PersistedConfig( "WEBHOOK_URL", "webhook_url", os.environ.get("WEBHOOK_URL", "") ) @@ -573,40 +573,40 @@ else: CHROMA_HTTP_SSL = os.environ.get("CHROMA_HTTP_SSL", "false").lower() == "true" # this uses the model defined in the Dockerfile ENV variable. If you dont use docker or docker based deployments such as k8s, the default embedding model will be used (sentence-transformers/all-MiniLM-L6-v2) -RAG_TOP_K = WrappedConfig( +RAG_TOP_K = PersistedConfig( "RAG_TOP_K", "rag.top_k", int(os.environ.get("RAG_TOP_K", "5")) ) -RAG_RELEVANCE_THRESHOLD = WrappedConfig( +RAG_RELEVANCE_THRESHOLD = PersistedConfig( "RAG_RELEVANCE_THRESHOLD", "rag.relevance_threshold", float(os.environ.get("RAG_RELEVANCE_THRESHOLD", "0.0")), ) -ENABLE_RAG_HYBRID_SEARCH = WrappedConfig( +ENABLE_RAG_HYBRID_SEARCH = PersistedConfig( "ENABLE_RAG_HYBRID_SEARCH", "rag.enable_hybrid_search", os.environ.get("ENABLE_RAG_HYBRID_SEARCH", "").lower() == "true", ) -ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = WrappedConfig( +ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = PersistedConfig( "ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION", "rag.enable_web_loader_ssl_verification", os.environ.get("ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION", "True").lower() == "true", ) -RAG_EMBEDDING_ENGINE = WrappedConfig( +RAG_EMBEDDING_ENGINE = PersistedConfig( "RAG_EMBEDDING_ENGINE", "rag.embedding_engine", os.environ.get("RAG_EMBEDDING_ENGINE", ""), ) -PDF_EXTRACT_IMAGES = WrappedConfig( +PDF_EXTRACT_IMAGES = PersistedConfig( "PDF_EXTRACT_IMAGES", "rag.pdf_extract_images", os.environ.get("PDF_EXTRACT_IMAGES", "False").lower() == "true", ) -RAG_EMBEDDING_MODEL = WrappedConfig( +RAG_EMBEDDING_MODEL = PersistedConfig( "RAG_EMBEDDING_MODEL", "rag.embedding_model", os.environ.get("RAG_EMBEDDING_MODEL", "sentence-transformers/all-MiniLM-L6-v2"), @@ -621,7 +621,7 @@ RAG_EMBEDDING_MODEL_TRUST_REMOTE_CODE = ( os.environ.get("RAG_EMBEDDING_MODEL_TRUST_REMOTE_CODE", "").lower() == "true" ) -RAG_RERANKING_MODEL = WrappedConfig( +RAG_RERANKING_MODEL = PersistedConfig( "RAG_RERANKING_MODEL", "rag.reranking_model", os.environ.get("RAG_RERANKING_MODEL", ""), @@ -665,10 +665,10 @@ if USE_CUDA.lower() == "true": else: DEVICE_TYPE = "cpu" -CHUNK_SIZE = WrappedConfig( +CHUNK_SIZE = PersistedConfig( "CHUNK_SIZE", "rag.chunk_size", int(os.environ.get("CHUNK_SIZE", "1500")) ) -CHUNK_OVERLAP = WrappedConfig( +CHUNK_OVERLAP = PersistedConfig( "CHUNK_OVERLAP", "rag.chunk_overlap", int(os.environ.get("CHUNK_OVERLAP", "100")), @@ -688,18 +688,18 @@ And answer according to the language of the user's question. Given the context information, answer the query. Query: [query]""" -RAG_TEMPLATE = WrappedConfig( +RAG_TEMPLATE = PersistedConfig( "RAG_TEMPLATE", "rag.template", os.environ.get("RAG_TEMPLATE", DEFAULT_RAG_TEMPLATE), ) -RAG_OPENAI_API_BASE_URL = WrappedConfig( +RAG_OPENAI_API_BASE_URL = PersistedConfig( "RAG_OPENAI_API_BASE_URL", "rag.openai_api_base_url", os.getenv("RAG_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL), ) -RAG_OPENAI_API_KEY = WrappedConfig( +RAG_OPENAI_API_KEY = PersistedConfig( "RAG_OPENAI_API_KEY", "rag.openai_api_key", os.getenv("RAG_OPENAI_API_KEY", OPENAI_API_KEY), @@ -709,7 +709,7 @@ ENABLE_RAG_LOCAL_WEB_FETCH = ( os.getenv("ENABLE_RAG_LOCAL_WEB_FETCH", "False").lower() == "true" ) -YOUTUBE_LOADER_LANGUAGE = WrappedConfig( +YOUTUBE_LOADER_LANGUAGE = PersistedConfig( "YOUTUBE_LOADER_LANGUAGE", "rag.youtube_loader_language", os.getenv("YOUTUBE_LOADER_LANGUAGE", "en").split(","), @@ -730,49 +730,49 @@ WHISPER_MODEL_AUTO_UPDATE = ( # Images #################################### -IMAGE_GENERATION_ENGINE = WrappedConfig( +IMAGE_GENERATION_ENGINE = PersistedConfig( "IMAGE_GENERATION_ENGINE", "image_generation.engine", os.getenv("IMAGE_GENERATION_ENGINE", ""), ) -ENABLE_IMAGE_GENERATION = WrappedConfig( +ENABLE_IMAGE_GENERATION = PersistedConfig( "ENABLE_IMAGE_GENERATION", "image_generation.enable", os.environ.get("ENABLE_IMAGE_GENERATION", "").lower() == "true", ) -AUTOMATIC1111_BASE_URL = WrappedConfig( +AUTOMATIC1111_BASE_URL = PersistedConfig( "AUTOMATIC1111_BASE_URL", "image_generation.automatic1111.base_url", os.getenv("AUTOMATIC1111_BASE_URL", ""), ) -COMFYUI_BASE_URL = WrappedConfig( +COMFYUI_BASE_URL = PersistedConfig( "COMFYUI_BASE_URL", "image_generation.comfyui.base_url", os.getenv("COMFYUI_BASE_URL", ""), ) -IMAGES_OPENAI_API_BASE_URL = WrappedConfig( +IMAGES_OPENAI_API_BASE_URL = PersistedConfig( "IMAGES_OPENAI_API_BASE_URL", "image_generation.openai.api_base_url", os.getenv("IMAGES_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL), ) -IMAGES_OPENAI_API_KEY = WrappedConfig( +IMAGES_OPENAI_API_KEY = PersistedConfig( "IMAGES_OPENAI_API_KEY", "image_generation.openai.api_key", os.getenv("IMAGES_OPENAI_API_KEY", OPENAI_API_KEY), ) -IMAGE_SIZE = WrappedConfig( +IMAGE_SIZE = PersistedConfig( "IMAGE_SIZE", "image_generation.size", os.getenv("IMAGE_SIZE", "512x512") ) -IMAGE_STEPS = WrappedConfig( +IMAGE_STEPS = PersistedConfig( "IMAGE_STEPS", "image_generation.steps", int(os.getenv("IMAGE_STEPS", 50)) ) -IMAGE_GENERATION_MODEL = WrappedConfig( +IMAGE_GENERATION_MODEL = PersistedConfig( "IMAGE_GENERATION_MODEL", "image_generation.model", os.getenv("IMAGE_GENERATION_MODEL", ""), @@ -782,22 +782,22 @@ IMAGE_GENERATION_MODEL = WrappedConfig( # Audio #################################### -AUDIO_OPENAI_API_BASE_URL = WrappedConfig( +AUDIO_OPENAI_API_BASE_URL = PersistedConfig( "AUDIO_OPENAI_API_BASE_URL", "audio.openai.api_base_url", os.getenv("AUDIO_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL), ) -AUDIO_OPENAI_API_KEY = WrappedConfig( +AUDIO_OPENAI_API_KEY = PersistedConfig( "AUDIO_OPENAI_API_KEY", "audio.openai.api_key", os.getenv("AUDIO_OPENAI_API_KEY", OPENAI_API_KEY), ) -AUDIO_OPENAI_API_MODEL = WrappedConfig( +AUDIO_OPENAI_API_MODEL = PersistedConfig( "AUDIO_OPENAI_API_MODEL", "audio.openai.api_model", os.getenv("AUDIO_OPENAI_API_MODEL", "tts-1"), ) -AUDIO_OPENAI_API_VOICE = WrappedConfig( +AUDIO_OPENAI_API_VOICE = PersistedConfig( "AUDIO_OPENAI_API_VOICE", "audio.openai.api_voice", os.getenv("AUDIO_OPENAI_API_VOICE", "alloy"), From 31cb6c985713b6027598d34ebfc7b2a2faa1f7ff Mon Sep 17 00:00:00 2001 From: Lior Kesos Date: Sun, 12 May 2024 10:56:32 +0300 Subject: [PATCH 17/29] Adding hebrew translation --- src/lib/i18n/locales/he-IL/translation.json | 619 ++++++++++++++++++++ src/lib/i18n/locales/languages.json | 4 + 2 files changed, 623 insertions(+) create mode 100644 src/lib/i18n/locales/he-IL/translation.json diff --git a/src/lib/i18n/locales/he-IL/translation.json b/src/lib/i18n/locales/he-IL/translation.json new file mode 100644 index 000000000..f2f96ced0 --- /dev/null +++ b/src/lib/i18n/locales/he-IL/translation.json @@ -0,0 +1,619 @@ +{ + "'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' או '-1' ללא תפוגה.", + "(Beta)": "(בטא)", + "(e.g. `sh webui.sh --api`)": "(למשל `sh webui.sh --api`)", + "(latest)": "(האחרון)", + "{{modelName}} is thinking...": "{{modelName}} חושב...", + "{{user}}'s Chats": "צ'אטים של {{user}}", + "{{webUIName}} Backend Required": "נדרש Backend של {{webUIName}}", + "a user": "משתמש", + "About": "אודות", + "Account": "חשבון", + "Accurate information": "מידע מדויק", + "Add a model": "הוסף מודל", + "Add a model tag name": "הוסף שם תג למודל", + "Add a short description about what this modelfile does": "הוסף תיאור קצר על מה שהקובץ מודל עושה", + "Add a short title for this prompt": "הוסף כותרת קצרה לפקודה זו", + "Add a tag": "הוסף תג", + "Add custom prompt": "הוסף פקודה מותאמת אישית", + "Add Docs": "הוסף מסמכים", + "Add Files": "הוסף קבצים", + "Add message": "הוסף הודעה", + "Add Model": "הוסף מודל", + "Add Tags": "הוסף תגים", + "Add User": "הוסף משתמש", + "Adjusting these settings will apply changes universally to all users.": "התאמת הגדרות אלו תחול על כל המשתמשים.", + "admin": "מנהל", + "Admin Panel": "לוח בקרה למנהל", + "Admin Settings": "הגדרות מנהל", + "Advanced Parameters": "פרמטרים מתקדמים", + "all": "הכל", + "All Documents": "כל המסמכים", + "All Users": "כל המשתמשים", + "Allow": "אפשר", + "Allow Chat Deletion": "אפשר מחיקת צ'אט", + "alphanumeric characters and hyphens": "תווים אלפאנומריים ומקפים", + "Already have an account?": "כבר יש לך חשבון?", + "an assistant": "עוזר", + "and": "וגם", + "and create a new shared link.": "וצור קישור משותף חדש.", + "API Base URL": "כתובת URL בסיסית ל-API", + "API Key": "מפתח API", + "API Key created.": "מפתח API נוצר.", + "API keys": "מפתחות API", + "API RPM": "RPM של API", + "April": "אפריל", + "Archive": "ארכיון", + "Archived Chats": "צ'אטים מאורכבים", + "are allowed - Activate this command by typing": "מותרים - הפעל פקודה זו על ידי הקלדה", + "Are you sure?": "האם אתה בטוח?", + "Attach file": "צרף קובץ", + "Attention to detail": "תשומת לב לפרטים", + "Audio": "אודיו", + "August": "אוגוסט", + "Auto-playback response": "תגובת השמעה אוטומטית", + "Auto-send input after 3 sec.": "שליחת קלט אוטומטית אחרי 3 שניות", + "AUTOMATIC1111 Base URL": "כתובת URL בסיסית של AUTOMATIC1111", + "AUTOMATIC1111 Base URL is required.": "נדרשת כתובת URL בסיסית של AUTOMATIC1111", + "available!": "זמין!", + "Back": "חזור", + "Bad Response": "תגובה שגויה", + "before": "לפני", + "Being lazy": "להיות עצלן", + "Builder Mode": "מצב בונה", + "Bypass SSL verification for Websites": "עקוף אימות SSL עבור אתרים", + "Cancel": "בטל", + "Categories": "קטגוריות", + "Change Password": "שנה סיסמה", + "Chat": "צ'אט", + "Chat History": "היסטוריית צ'אט", + "Chat History is off for this browser.": "היסטוריית הצ'אט כבויה לדפדפן זה.", + "Chats": "צ'אטים", + "Check Again": "בדוק שוב", + "Check for updates": "בדוק עדכונים", + "Checking for updates...": "בודק עדכונים...", + "Choose a model before saving...": "בחר מודל לפני השמירה...", + "Chunk Overlap": "חפיפת נתונים", + "Chunk Params": "פרמטרי נתונים", + "Chunk Size": "גודל נתונים", + "Citation": "ציטוט", + "Click here for help.": "לחץ כאן לעזרה.", + "Click here to": "לחץ כאן כדי", + "Click here to check other modelfiles.": "לחץ כאן לבדיקת קבצי מודלים אחרים.", + "Click here to select": "לחץ כאן לבחירה", + "Click here to select a csv file.": "לחץ כאן לבחירת קובץ csv.", + "Click here to select documents.": "לחץ כאן לבחירת מסמכים.", + "click here.": "לחץ כאן.", + "Click on the user role button to change a user's role.": "לחץ על כפתור תפקיד המשתמש כדי לשנות את תפקיד המשתמש.", + "Close": "סגור", + "Collection": "אוסף", + "ComfyUI": "ComfyUI", + "ComfyUI Base URL": "כתובת URL בסיסית של ComfyUI", + "ComfyUI Base URL is required.": "נדרשת כתובת URL בסיסית של ComfyUI", + "Command": "פקודה", + "Confirm Password": "אשר סיסמה", + "Connections": "חיבורים", + "Content": "תוכן", + "Context Length": "אורך הקשר", + "Continue Response": "המשך תגובה", + "Conversation Mode": "מצב שיחה", + "Copied shared chat URL to clipboard!": "העתקת כתובת URL של צ'אט משותף ללוח!", + "Copy": "העתק", + "Copy last code block": "העתק את בלוק הקוד האחרון", + "Copy last response": "העתק את התגובה האחרונה", + "Copy Link": "העתק קישור", + "Copying to clipboard was successful!": "ההעתקה ללוח הייתה מוצלחת!", + "Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "צור ביטוי תמציתי של 3-5 מילים ככותרת לשאילתה הבאה, תוך שמירה מדויקת על מגבלת 3-5 המילים והימנעות משימוש במילה 'כותרת':", + "Create a modelfile": "צור קובץ מודל", + "Create Account": "צור חשבון", + "Create new key": "צור מפתח חדש", + "Create new secret key": "צור מפתח סודי חדש", + "Created at": "נוצר ב", + "Created At": "נוצר ב", + "Current Model": "המודל הנוכחי", + "Current Password": "הסיסמה הנוכחית", + "Custom": "מותאם אישית", + "Customize Ollama models for a specific purpose": "התאמה אישית של מודלים של Ollama למטרה מסוימת", + "Dark": "כהה", + "Dashboard": "לוח בקרה", + "Database": "מסד נתונים", + "DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm", + "December": "דצמבר", + "Default": "ברירת מחדל", + "Default (Automatic1111)": "ברירת מחדל (Automatic1111)", + "Default (SentenceTransformers)": "ברירת מחדל (SentenceTransformers)", + "Default (Web API)": "ברירת מחדל (Web API)", + "Default model updated": "המודל המוגדר כברירת מחדל עודכן", + "Default Prompt Suggestions": "הצעות ברירת מחדל לפקודות", + "Default User Role": "תפקיד משתמש ברירת מחדל", + "delete": "מחק", + "Delete": "מחק", + "Delete a model": "מחק מודל", + "Delete chat": "מחק צ'אט", + "Delete Chat": "מחק צ'אט", + "Delete Chats": "מחק צ'אטים", + "delete this link": "מחק את הקישור הזה", + "Delete User": "מחק משתמש", + "Deleted {{deleteModelTag}}": "נמחק {{deleteModelTag}}", + "Deleted {{tagName}}": "נמחק {{tagName}}", + "Description": "תיאור", + "Didn't fully follow instructions": "לא עקב אחרי ההוראות באופן מלא", + "Disabled": "מושבת", + "Discover a modelfile": "גלה קובץ מודל", + "Discover a prompt": "גלה פקודה", + "Discover, download, and explore custom prompts": "גלה, הורד, וחקור פקודות מותאמות אישית", + "Discover, download, and explore model presets": "גלה, הורד, וחקור הגדרות מודל מוגדרות מראש", + "Display the username instead of You in the Chat": "הצג את שם המשתמש במקום 'אתה' בצ'אט", + "Document": "מסמך", + "Document Settings": "הגדרות מסמך", + "Documents": "מסמכים", + "does not make any external connections, and your data stays securely on your locally hosted server.": "לא מבצע חיבורים חיצוניים, והנתונים שלך נשמרים באופן מאובטח בשרת המקומי שלך.", + "Don't Allow": "אל תאפשר", + "Don't have an account?": "אין לך חשבון?", + "Don't like the style": "לא אוהב את הסגנון", + "Download": "הורד", + "Download canceled": "ההורדה בוטלה", + "Download Database": "הורד מסד נתונים", + "Drop any files here to add to the conversation": "גרור כל קובץ לכאן כדי להוסיף לשיחה", + "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "למשל '30s', '10m'. יחידות זמן חוקיות הן 's', 'm', 'h'.", + "Edit": "ערוך", + "Edit Doc": "ערוך מסמך", + "Edit User": "ערוך משתמש", + "Email": "דוא\"ל", + "Embedding Model": "מודל הטמעה", + "Embedding Model Engine": "מנוע מודל הטמעה", + "Embedding model set to \"{{embedding_model}}\"": "מודל ההטמעה הוגדר ל-\"{{embedding_model}}\"", + "Enable Chat History": "הפעל היסטוריית צ'אט", + "Enable New Sign Ups": "אפשר הרשמות חדשות", + "Enabled": "מופעל", + "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "ודא שקובץ ה-CSV שלך כולל 4 עמודות בסדר הבא: שם, דוא\"ל, סיסמה, תפקיד.", + "Enter {{role}} message here": "הזן הודעת {{role}} כאן", + "Enter Chunk Overlap": "הזן חפיפת נתונים", + "Enter Chunk Size": "הזן גודל נתונים", + "Enter Image Size (e.g. 512x512)": "הזן גודל תמונה (למשל 512x512)", + "Enter language codes": "הזן קודי שפה", + "Enter LiteLLM API Base URL (litellm_params.api_base)": "הזן כתובת URL בסיסית ל-API של LiteLLM (litellm_params.api_base)", + "Enter LiteLLM API Key (litellm_params.api_key)": "הזן מפתח API של LiteLLM (litellm_params.api_key)", + "Enter LiteLLM API RPM (litellm_params.rpm)": "הזן RPM של API של LiteLLM (litellm_params.rpm)", + "Enter LiteLLM Model (litellm_params.model)": "הזן מודל LiteLLM (litellm_params.model)", + "Enter Max Tokens (litellm_params.max_tokens)": "הזן מספר מקסימלי של טוקנים (litellm_params.max_tokens)", + "Enter model tag (e.g. {{modelTag}})": "הזן תג מודל (למשל {{modelTag}})", + "Enter Number of Steps (e.g. 50)": "הזן מספר שלבים (למשל 50)", + "Enter Score": "הזן ציון", + "Enter stop sequence": "הזן רצף עצירה", + "Enter Top K": "הזן Top K", + "Enter URL (e.g. http://127.0.0.1:7860/)": "הזן כתובת URL (למשל http://127.0.0.1:7860/)", + "Enter URL (e.g. http://localhost:11434)": "הזן כתובת URL (למשל http://localhost:11434)", + "Enter Your Email": "הזן את דוא\"ל שלך", + "Enter Your Full Name": "הזן את שמך המלא", + "Enter Your Password": "הזן את הסיסמה שלך", + "Enter Your Role": "הזן את התפקיד שלך", + "Experimental": "ניסיוני", + "Export All Chats (All Users)": "ייצוא כל הצ'אטים (כל המשתמשים)", + "Export Chats": "ייצוא צ'אטים", + "Export Documents Mapping": "ייצוא מיפוי מסמכים", + "Export Modelfiles": "ייצוא קבצי מודלים", + "Export Prompts": "ייצוא פקודות", + "Failed to create API Key.": "יצירת מפתח API נכשלה.", + "Failed to read clipboard contents": "קריאת תוכן הלוח נכשלה", + "February": "פברואר", + "Feel free to add specific details": "נא להוסיף פרטים ספציפיים לפי רצון", + "File Mode": "מצב קובץ", + "File not found.": "הקובץ לא נמצא.", + "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "התגלתה הזיית טביעת אצבע: לא ניתן להשתמש בראשי תיבות כאווטאר. משתמש בתמונת פרופיל ברירת מחדל.", + "Fluidly stream large external response chunks": "שידור נתונים חיצוניים בקצב רציף", + "Focus chat input": "מיקוד הקלט לצ'אט", + "Followed instructions perfectly": "עקב אחר ההוראות במושלמות", + "Format your variables using square brackets like this:": "עצב את המשתנים שלך באמצעות סוגריים מרובעים כך:", + "From (Base Model)": "מ (מודל בסיס)", + "Full Screen Mode": "מצב מסך מלא", + "General": "כללי", + "General Settings": "הגדרות כלליות", + "Generation Info": "מידע על היצירה", + "Good Response": "תגובה טובה", + "has no conversations.": "אין שיחות.", + "Hello, {{name}}": "שלום, {{name}}", + "Help": "עזרה", + "Hide": "הסתר", + "Hide Additional Params": "הסתר פרמטרים נוספים", + "How can I help you today?": "כיצד אוכל לעזור לך היום?", + "Hybrid Search": "חיפוש היברידי", + "Image Generation (Experimental)": "יצירת תמונות (ניסיוני)", + "Image Generation Engine": "מנוע יצירת תמונות", + "Image Settings": "הגדרות תמונה", + "Images": "תמונות", + "Import Chats": "יבוא צ'אטים", + "Import Documents Mapping": "יבוא מיפוי מסמכים", + "Import Modelfiles": "יבוא קבצי מודלים", + "Import Prompts": "יבוא פקודות", + "Include `--api` flag when running stable-diffusion-webui": "כלול את הדגל `--api` בעת הרצת stable-diffusion-webui", + "Input commands": "פקודות קלט", + "Interface": "ממשק", + "Invalid Tag": "תג לא חוקי", + "January": "ינואר", + "join our Discord for help.": "הצטרף ל-Discord שלנו לעזרה.", + "JSON": "JSON", + "July": "יולי", + "June": "יוני", + "JWT Expiration": "תפוגת JWT", + "JWT Token": "אסימון JWT", + "Keep Alive": "השאר פעיל", + "Keyboard shortcuts": "קיצורי מקלדת", + "Language": "שפה", + "Last Active": "פעיל לאחרונה", + "Light": "בהיר", + "Listening...": "מאזין...", + "LLMs can make mistakes. Verify important information.": "מודלים בשפה טבעית יכולים לטעות. אמת מידע חשוב.", + "Made by OpenWebUI Community": "נוצר על ידי קהילת OpenWebUI", + "Make sure to enclose them with": "ודא להקיף אותם עם", + "Manage LiteLLM Models": "נהל מודלים של LiteLLM", + "Manage Models": "נהל מודלים", + "Manage Ollama Models": "נהל מודלים של Ollama", + "March": "מרץ", + "Max Tokens": "מקסימום טוקנים", + "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "ניתן להוריד מקסימום 3 מודלים בו זמנית. אנא נסה שוב מאוחר יותר.", + "May": "מאי", + "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "הודעות שתשלח לאחר יצירת הקישור שלך לא ישותפו. משתמשים עם הכתובת URL יוכלו לצפות בצ'אט המשותף.", + "Minimum Score": "ציון מינימלי", + "Mirostat": "Mirostat", + "Mirostat Eta": "Mirostat Eta", + "Mirostat Tau": "Mirostat Tau", + "MMMM DD, YYYY": "DD בMMMM, YYYY", + "MMMM DD, YYYY HH:mm": "DD בMMMM, YYYY HH:mm", + "Model '{{modelName}}' has been successfully downloaded.": "המודל '{{modelName}}' הורד בהצלחה.", + "Model '{{modelTag}}' is already in queue for downloading.": "המודל '{{modelTag}}' כבר בתור להורדה.", + "Model {{modelId}} not found": "המודל {{modelId}} לא נמצא", + "Model {{modelName}} already exists.": "המודל {{modelName}} כבר קיים.", + "Model filesystem path detected. Model shortname is required for update, cannot continue.": "נתיב מערכת הקבצים של המודל זוהה. נדרש שם קצר של המודל לעדכון, לא ניתן להמשיך.", + "Model Name": "שם המודל", + "Model not selected": "לא נבחר מודל", + "Model Tag Name": "שם תג המודל", + "Model Whitelisting": "רישום לבן של מודלים", + "Model(s) Whitelisted": "מודלים שנכללו ברשימה הלבנה", + "Modelfile": "קובץ מודל", + "Modelfile Advanced Settings": "הגדרות מתקדמות לקובץ מודל", + "Modelfile Content": "תוכן קובץ מודל", + "Modelfiles": "קבצי מודל", + "Models": "מודלים", + "More": "עוד", + "My Documents": "המסמכים שלי", + "My Modelfiles": "קבצי המודל שלי", + "My Prompts": "הפקודות שלי", + "Name": "שם", + "Name Tag": "תג שם", + "Name your modelfile": "תן שם לקובץ המודל שלך", + "New Chat": "צ'אט חדש", + "New Password": "סיסמה חדשה", + "No results found": "לא נמצאו תוצאות", + "No source available": "אין מקור זמין", + "Not factually correct": "לא נכון מבחינה עובדתית", + "Not sure what to add?": "לא בטוח מה להוסיף?", + "Not sure what to write? Switch to": "לא בטוח מה לכתוב? החלף ל", + "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "הערה: אם תקבע ציון מינימלי, החיפוש יחזיר רק מסמכים עם ציון שגבוה או שווה לציון המינימלי.", + "Notifications": "התראות", + "November": "נובמבר", + "October": "אוקטובר", + "Off": "כבוי", + "Okay, Let's Go!": "בסדר, בואו נתחיל!", + "OLED Dark": "OLED כהה", + "Ollama": "Ollama", + "Ollama Base URL": "כתובת URL בסיסית של Ollama", + "Ollama Version": "גרסת Ollama", + "On": "פועל", + "Only": "רק", + "Only alphanumeric characters and hyphens are allowed in the command string.": "רק תווים אלפאנומריים ומקפים מותרים במחרוזת הפקודה.", + "Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "אופס! תחזיק מעמד! הקבצים שלך עדיין בתהליך העיבוד. אנו מבשלים אותם לשלמות. נא להתאזר בסבלנות ונודיע לך ברגע שיהיו מוכנים.", + "Oops! Looks like the URL is invalid. Please double-check and try again.": "אופס! נראה שהכתובת URL אינה תקינה. אנא בדוק שוב ונסה שנית.", + "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "אופס! אתה משתמש בשיטה לא נתמכת (רק חזית). אנא שרת את ממשק המשתמש האינטרנטי מהשרת האחורי.", + "Open": "פתח", + "Open AI": "Open AI", + "Open AI (Dall-E)": "Open AI (Dall-E)", + "Open new chat": "פתח צ'אט חדש", + "OpenAI": "OpenAI", + "OpenAI API": "API של OpenAI", + "OpenAI API Config": "תצורת API של OpenAI", + "OpenAI API Key is required.": "נדרש מפתח API של OpenAI.", + "OpenAI URL/Key required.": "נדרשת כתובת URL/מפתח של OpenAI.", + "or": "או", + "Other": "אחר", + "Overview": "סקירה כללית", + "Parameters": "פרמטרים", + "Password": "סיסמה", + "PDF document (.pdf)": "מסמך PDF (.pdf)", + "PDF Extract Images (OCR)": "חילוץ תמונות מ-PDF (OCR)", + "pending": "ממתין", + "Permission denied when accessing microphone: {{error}}": "ההרשאה נדחתה בעת גישה למיקרופון: {{error}}", + "Plain text (.txt)": "טקסט פשוט (.txt)", + "Playground": "אזור משחקים", + "Positive attitude": "גישה חיובית", + "Previous 30 days": "30 הימים הקודמים", + "Previous 7 days": "7 הימים הקודמים", + "Profile Image": "תמונת פרופיל", + "Prompt": "פקודה", + "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "פקודה (למשל, ספר לי עובדה מעניינת על האימפריה הרומית)", + "Prompt Content": "תוכן הפקודה", + "Prompt suggestions": "הצעות לפקודות", + "Prompts": "פקודות", + "Pull \"{{searchValue}}\" from Ollama.com": "משוך \"{{searchValue}}\" מ-Ollama.com", + "Pull a model from Ollama.com": "משוך מודל מ-Ollama.com", + "Pull Progress": "משוך התקדמות", + "Query Params": "פרמטרי שאילתה", + "RAG Template": "תבנית RAG", + "Raw Format": "פורמט גולמי", + "Read Aloud": "קרא בקול", + "Record voice": "הקלט קול", + "Redirecting you to OpenWebUI Community": "מפנה אותך לקהילת OpenWebUI", + "Refused when it shouldn't have": "נדחה כאשר לא היה צריך", + "Regenerate": "הפק מחדש", + "Release Notes": "הערות שחרור", + "Remove": "הסר", + "Remove Model": "הסר מודל", + "Rename": "שנה שם", + "Repeat Last N": "חזור על ה-N האחרונים", + "Repeat Penalty": "עונש חזרה", + "Request Mode": "מצב בקשה", + "Reranking Model": "מודל דירוג מחדש", + "Reranking model disabled": "מודל דירוג מחדש מושבת", + "Reranking model set to \"{{reranking_model}}\"": "מודל דירוג מחדש הוגדר ל-\"{{reranking_model}}\"", + "Reset Vector Storage": "איפוס אחסון וקטורים", + "Response AutoCopy to Clipboard": "העתקה אוטומטית של תגובה ללוח", + "Role": "תפקיד", + "Rosé Pine": "Rosé Pine", + "Rosé Pine Dawn": "Rosé Pine Dawn", + "Save": "שמור", + "Save & Create": "שמור וצור", + "Save & Submit": "שמור ושלח", + "Save & Update": "שמור ועדכן", + "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "שמירת יומני צ'אט ישירות באחסון הדפדפן שלך אינה נתמכת יותר. אנא הקדש רגע להוריד ולמחוק את יומני הצ'אט שלך על ידי לחיצה על הכפתור למטה. אל דאגה, באפשרותך לייבא מחדש בקלות את יומני הצ'אט שלך לשרת האחורי דרך", + "Scan": "סרוק", + "Scan complete!": "הסריקה הושלמה!", + "Scan for documents from {{path}}": "סרוק מסמכים מ-{{path}}", + "Search": "חפש", + "Search a model": "חפש מודל", + "Search Documents": "חפש מסמכים", + "Search Prompts": "חפש פקודות", + "See readme.md for instructions": "ראה את readme.md להוראות", + "See what's new": "ראה מה חדש", + "Seed": "זרע", + "Select a mode": "בחר מצב", + "Select a model": "בחר מודל", + "Select an Ollama instance": "בחר מופע של Ollama", + "Select model": "בחר מודל", + "Send a Message": "שלח הודעה", + "Send message": "שלח הודעה", + "September": "ספטמבר", + "Server connection verified": "החיבור לשרת אומת", + "Set as default": "הגדר כברירת מחדל", + "Set Default Model": "הגדר מודל ברירת מחדל", + "Set embedding model (e.g. {{model}})": "הגדר מודל הטמעה (למשל {{model}})", + "Set Image Size": "הגדר גודל תמונה", + "Set Model": "הגדר מודל", + "Set reranking model (e.g. {{model}})": "הגדר מודל דירוג מחדש (למשל {{model}})", + "Set Steps": "הגדר שלבים", + "Set Title Auto-Generation Model": "הגדר מודל יצירת כותרת אוטומטית", + "Set Voice": "הגדר קול", + "Settings": "הגדרות", + "Settings saved successfully!": "ההגדרות נשמרו בהצלחה!", + "Share": "שתף", + "Share Chat": "שתף צ'אט", + "Share to OpenWebUI Community": "שתף לקהילת OpenWebUI", + "short-summary": "סיכום קצר", + "Show": "הצג", + "Show Additional Params": "הצג פרמטרים נוספים", + "Show shortcuts": "הצג קיצורי דרך", + "Showcased creativity": "הצגת יצירתיות", + "sidebar": "סרגל צד", + "Sign In": "התחבר", + "Sign out": "התנתק", + "Signed In": "מחובר", + "Simulation": "סימולציה", + "Single Sign-On": "כניסה אחת לכל המערכות", + "Site": "אתר", + "Size": "גודל", + "Skipped": "דלג", + "Small size": "גודל קטן", + "Sort by": "מיין לפי", + "Source code": "קוד מקור", + "Source Code View": "הצגת קוד מקור", + "Source not available": "המקור לא זמין", + "Specify a different location": "ציין מיקום אחר", + "Speech Recognition": "זיהוי דיבור", + "Split": "חלק", + "Split screen": "מסך מחולק", + "SSH Tunnel": "מנהרת SSH", + "SSH Tunnel Configuration": "תצורת מנהרת SSH", + "Start": "התחל", + "Start Over": "התחל מחדש", + "Start with a new search": "התחל עם חיפוש חדש", + "Started": "התחיל", + "Status": "מצב", + "Step": "שלב", + "Stop": "עצור", + "Storage": "אחסון", + "Storage Configuration": "תצורת אחסון", + "Storage path": "נתיב אחסון", + "Submit": "שלח", + "Submit Feedback": "שלח משוב", + "Submit request": "שלח בקשה", + "Success": "הצלחה", + "Successfully saved": "נשמר בהצלחה", + "Suggest a correction": "הצע תיקון", + "Suggest changes": "הצע שינויים", + "Suggest improvement": "הצע שיפור", + "Suggested Content": "תוכן מוצע", + "Suggested Model": "מודל מוצע", + "Suggested Prompts": "פקודות מוצעות", + "Summary": "סיכום", + "Support": "תמיכה", + "Support portal": "פורטל תמיכה", + "Supported Files": "קבצים נתמכים", + "Suspend": "השעה", + "Switch": "החלף", + "Switch accounts": "החלף חשבונות", + "Switch Languages": "החלף שפות", + "Switch model": "החלף מודל", + "Switch Theme": "החלף נושא", + "Switch to a different model": "עבור למודל אחר", + "System": "מערכת", + "System Check": "בדיקת מערכת", + "System Settings": "הגדרות מערכת", + "Tab": "לשונית", + "Table of Contents": "תוכן העניינים", + "Tag": "תג", + "Take a look at our new features!": "הצצה בתכונות החדשות שלנו!", + "Take Snapshot": "צלם תמונה", + "Tasks": "משימות", + "Technical Details": "פרטים טכניים", + "Template": "תבנית", + "Terms of Service": "תנאי שירות", + "Test Connection": "בדוק חיבור", + "Text": "טקסט", + "Text Area": "אזור טקסט", + "Text Editor": "עורך טקסט", + "Text Field": "שדה טקסט", + "Text Input": "קלט טקסט", + "Text Settings": "הגדרות טקסט", + "Text-to-Speech": "טקסט לדיבור", + "Text-to-Speech Engine": "מנוע טקסט לדיבור", + "Thanks": "תודה", + "Thanks for your feedback!": "תודה על המשוב שלך!", + "The latest updates": "העדכונים האחרונים", + "The new standard in online communication": "התקן החדש בתקשורת מקוונת", + "Theme": "נושא", + "Theme Settings": "הגדרות נושא", + "There are no new updates available": "אין עדכונים חדשים זמינים", + "This action cannot be undone": "פעולה זו לא ניתנת לביטול", + "This is a critical update": "זהו עדכון קריטי", + "This is a required field": "זהו שדה חובה", + "This month": "החודש", + "This week": "השבוע", + "Time": "זמן", + "Time Limit": "מגבלת זמן", + "Time Zone": "אזור זמן", + "To": "אל", + "To do list": "רשימת משימות", + "Toggle": "החלף מצב", + "Toggle Dark Mode": "החלף מצב כהה", + "Toggle Light Mode": "החלף מצב בהיר", + "Toggle navigation": "החלף ניווט", + "Token": "אסימון", + "Toolbar": "סרגל כלים", + "Toolbox": "ארגז כלים", + "Top": "למעלה", + "Total": "סך הכל", + "Trace": "עקוב", + "Track": "עקוב אחרי", + "Tracking": "מעקב", + "Traditional": "מסורתי", + "Train": "רכבת", + "Training": "הדרכה", + "Transaction": "עסקה", + "Transcript": "תמליל", + "Transfer": "העברה", + "Transform": "הפוך", + "Translate": "תרגם", + "Translation": "תרגום", + "Transparency": "שקיפות", + "Transport": "תחבורה", + "Trending": "טרנדים", + "Trial": "ניסיון", + "Triggers": "מפעילים", + "Troubleshoot": "פתרון בעיות", + "Troubleshooting": "פתרון בעיות", + "True": "נכון", + "Trust": "אמון", + "Try Again": "נסה שוב", + "Type": "סוג", + "Type your message": "הקלד את הודעתך", + "Typing": "הקלדה", + "UI Components": "רכיבי ממשק משתמש", + "Unarchive": "בטל ארכיבה", + "Undo": "בטל", + "Uninstall": "הסר התקנה", + "Unique": "ייחודי", + "Unit": "יחידה", + "Universal": "אוניברסלי", + "Unknown": "לא ידוע", + "Unlimited": "לא מוגבל", + "Unlock": "פתח נעילה", + "Unread": "לא נקרא", + "Unsubscribe": "בטל רישום", + "Update": "עדכן", + "Update Available": "עדכון זמין", + "Update Profile": "עדכן פרופיל", + "Updated": "עודכן", + "Upload": "העלה", + "Upload File": "העלה קובץ", + "Upload Image": "העלה תמונה", + "Uptime": "זמן פעילות", + "URL": "כתובת אתר", + "Usage": "שימוש", + "Use": "השתמש", + "User": "משתמש", + "User Agreement": "הסכם משתמש", + "User Guide": "מדריך משתמש", + "User Interface": "ממשק משתמש", + "User Management": "ניהול משתמשים", + "User Profile": "פרופיל משתמש", + "Username": "שם משתמש", + "Users": "משתמשים", + "Utility": "שימושיות", + "Validate": "אמת", + "Validation": "אימות", + "Value": "ערך", + "Values": "ערכים", + "Variable": "משתנה", + "Variants": "נגזרות", + "Various": "שונים", + "Version": "גרסה", + "View": "הצג", + "View Details": "הצג פרטים", + "View more": "הצג עוד", + "Visibility": "נראות", + "Visible": "נראה", + "Visit": "בקר", + "Visitor": "מבקר", + "Visual": "חזותי", + "Vocabulary": "אוצר מילים", + "Voice": "קול", + "Voice Command": "פקודת קול", + "Volume": "נפח", + "Vote": "הצבע", + "Voucher": "שובר", + "Wait": "חכה", + "Waiting": "ממתין", + "Warning": "אזהרה", + "Watch": "צפה", + "Web": "רשת", + "Web Access": "גישה לרשת", + "Web Application": "יישום רשת", + "Web Service": "שירות רשת", + "Website": "אתר אינטרנט", + "Week": "שבוע", + "Welcome": "ברוך הבא", + "What's New": "מה חדש", + "Widget": "וידג'ט", + "Width": "רוחב", + "Window": "חלון", + "Windows": "חלונות", + "Winner": "מנצח", + "Wireless": "אלחוטי", + "Wisdom": "חוכמה", + "Withdraw": "משוך", + "Work": "עבודה", + "Workaround": "פתרון זמני", + "Workflow": "זרימת עבודה", + "Workspace": "סביבת עבודה", + "World": "עולם", + "Write": "כתוב", + "Writer": "כותב", + "Writing": "כתיבה", + "XML": "XML", + "Year": "שנה", + "Yes": "כן", + "Yesterday": "אתמול", + "You": "אתה", + "YouTube": "יוטיוב", + "Zone": "אזור", + "Zoom": "זום" +} diff --git a/src/lib/i18n/locales/languages.json b/src/lib/i18n/locales/languages.json index 62aa01b4a..8173ab854 100644 --- a/src/lib/i18n/locales/languages.json +++ b/src/lib/i18n/locales/languages.json @@ -47,6 +47,10 @@ "code": "fr-FR", "title": "French (France)" }, + { + "code": "he-IL", + "title": "עברית (Hebrew)" + }, { "code": "hi-IN", "title": "Hindi (हिंदी)" From b63aca534b0f17e74f25f4462c6bc9f02eec2c65 Mon Sep 17 00:00:00 2001 From: aguvener <90110302+aguvener@users.noreply.github.com> Date: Sun, 12 May 2024 12:41:08 +0300 Subject: [PATCH 18/29] Update translation.json --- src/lib/i18n/locales/tr-TR/translation.json | 114 ++++++++++---------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index 5510678ad..ff5a76140 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -15,7 +15,7 @@ "Add a short description about what this modelfile does": "Bu model dosyasının ne yaptığı hakkında kısa bir açıklama ekleyin", "Add a short title for this prompt": "Bu prompt için kısa bir başlık ekleyin", "Add a tag": "Bir etiket ekleyin", - "Add custom prompt": "", + "Add custom prompt": "Özel prompt ekle", "Add Docs": "Dökümanlar Ekle", "Add Files": "Dosyalar Ekle", "Add message": "Mesaj ekle", @@ -28,7 +28,7 @@ "Admin Settings": "Yönetici Ayarları", "Advanced Parameters": "Gelişmiş Parametreler", "all": "tümü", - "All Documents": "", + "All Documents": "Tüm Belgeler", "All Users": "Tüm Kullanıcılar", "Allow": "İzin ver", "Allow Chat Deletion": "Sohbet Silmeye İzin Ver", @@ -36,21 +36,21 @@ "Already have an account?": "Zaten bir hesabınız mı var?", "an assistant": "bir asistan", "and": "ve", - "and create a new shared link.": "", + "and create a new shared link.": "ve yeni bir paylaşılan bağlantı oluşturun.", "API Base URL": "API Temel URL", "API Key": "API Anahtarı", "API Key created.": "API Anahtarı oluşturuldu.", "API keys": "API anahtarları", "API RPM": "API RPM", - "April": "", + "April": "Nisan", "Archive": "Arşiv", "Archived Chats": "Arşivlenmiş Sohbetler", "are allowed - Activate this command by typing": "izin verilir - Bu komutu yazarak etkinleştirin", "Are you sure?": "Emin misiniz?", - "Attach file": "", + "Attach file": "Dosya ekle", "Attention to detail": "Ayrıntılara dikkat", "Audio": "Ses", - "August": "", + "August": "Ağustos", "Auto-playback response": "Yanıtı otomatik oynatma", "Auto-send input after 3 sec.": "3 saniye sonra otomatik olarak gönder", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 Temel URL", @@ -58,10 +58,10 @@ "available!": "mevcut!", "Back": "Geri", "Bad Response": "Kötü Yanıt", - "before": "", + "before": "önce", "Being lazy": "Tembelleşiyor", "Builder Mode": "Oluşturucu Modu", - "Bypass SSL verification for Websites": "", + "Bypass SSL verification for Websites": "Web Siteleri için SSL doğrulamasını atlayın", "Cancel": "İptal", "Categories": "Kategoriler", "Change Password": "Parola Değiştir", @@ -76,9 +76,9 @@ "Chunk Overlap": "Chunk Çakışması", "Chunk Params": "Chunk Parametreleri", "Chunk Size": "Chunk Boyutu", - "Citation": "", + "Citation": "Alıntı", "Click here for help.": "Yardım için buraya tıklayın.", - "Click here to": "", + "Click here to": "Şunu yapmak için buraya tıklayın:", "Click here to check other modelfiles.": "Diğer model dosyalarını kontrol etmek için buraya tıklayın.", "Click here to select": "Seçmek için buraya tıklayın", "Click here to select a csv file.": "Bir CSV dosyası seçmek için buraya tıklayın.", @@ -95,7 +95,7 @@ "Connections": "Bağlantılar", "Content": "İçerik", "Context Length": "Bağlam Uzunluğu", - "Continue Response": "", + "Continue Response": "Yanıta Devam Et", "Conversation Mode": "Sohbet Modu", "Copied shared chat URL to clipboard!": "Paylaşılan sohbet URL'si panoya kopyalandı!", "Copy": "Kopyala", @@ -106,8 +106,8 @@ "Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "Aşağıdaki sorgu için başlık olarak 3-5 kelimelik kısa ve öz bir ifade oluşturun, 3-5 kelime sınırına kesinlikle uyun ve 'başlık' kelimesini kullanmaktan kaçının:", "Create a modelfile": "Bir model dosyası oluştur", "Create Account": "Hesap Oluştur", - "Create new key": "", - "Create new secret key": "", + "Create new key": "Yeni anahtar oluştur", + "Create new secret key": "Yeni gizli anahtar oluştur", "Created at": "Oluşturulma tarihi", "Created At": "Şu Tarihte Oluşturuldu:", "Current Model": "Mevcut Model", @@ -115,10 +115,10 @@ "Custom": "Özel", "Customize Ollama models for a specific purpose": "Ollama modellerini belirli bir amaç için özelleştirin", "Dark": "Koyu", - "Dashboard": "", + "Dashboard": "Panel", "Database": "Veritabanı", "DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm", - "December": "", + "December": "Aralık", "Default": "Varsayılan", "Default (Automatic1111)": "Varsayılan (Automatic1111)", "Default (SentenceTransformers)": "Varsayılan (SentenceTransformers)", @@ -132,7 +132,7 @@ "Delete chat": "Sohbeti sil", "Delete Chat": "Sohbeti Sil", "Delete Chats": "Sohbetleri Sil", - "delete this link": "", + "delete this link": "bu bağlantıyı sil", "Delete User": "Kullanıcıyı Sil", "Deleted {{deleteModelTag}}": "{{deleteModelTag}} silindi", "Deleted {{tagName}}": "{{tagName}} silindi", @@ -152,7 +152,7 @@ "Don't have an account?": "Hesabınız yok mu?", "Don't like the style": "Tarzını beğenmedim", "Download": "İndir", - "Download canceled": "", + "Download canceled": "İndirme iptal edildi", "Download Database": "Veritabanını İndir", "Drop any files here to add to the conversation": "Sohbete eklemek istediğiniz dosyaları buraya bırakın", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "örn. '30s', '10m'. Geçerli zaman birimleri 's', 'm', 'h'.", @@ -160,7 +160,7 @@ "Edit Doc": "Belgeyi Düzenle", "Edit User": "Kullanıcıyı Düzenle", "Email": "E-posta", - "Embedding Model": "", + "Embedding Model": "Gömme Modeli", "Embedding Model Engine": "Gömme Modeli Motoru", "Embedding model set to \"{{embedding_model}}\"": "Gömme modeli \"{{embedding_model}}\" olarak ayarlandı", "Enable Chat History": "Sohbet Geçmişini Etkinleştir", @@ -171,7 +171,7 @@ "Enter Chunk Overlap": "Chunk Örtüşmesini Girin", "Enter Chunk Size": "Chunk Boyutunu Girin", "Enter Image Size (e.g. 512x512)": "Görüntü Boyutunu Girin (örn. 512x512)", - "Enter language codes": "", + "Enter language codes": "Dil kodlarını girin", "Enter LiteLLM API Base URL (litellm_params.api_base)": "LiteLLM API Ana URL'sini Girin (litellm_params.api_base)", "Enter LiteLLM API Key (litellm_params.api_key)": "LiteLLM API Anahtarını Girin (litellm_params.api_key)", "Enter LiteLLM API RPM (litellm_params.rpm)": "LiteLLM API RPM'ini Girin (litellm_params.rpm)", @@ -183,7 +183,7 @@ "Enter stop sequence": "Durdurma dizisini girin", "Enter Top K": "Top K'yı girin", "Enter URL (e.g. http://127.0.0.1:7860/)": "URL'yi Girin (örn. http://127.0.0.1:7860/)", - "Enter URL (e.g. http://localhost:11434)": "", + "Enter URL (e.g. http://localhost:11434)": "URL'yi Girin (e.g. http://localhost:11434)", "Enter Your Email": "E-postanızı Girin", "Enter Your Full Name": "Tam Adınızı Girin", "Enter Your Password": "Parolanızı Girin", @@ -196,7 +196,7 @@ "Export Prompts": "Promptları Dışa Aktar", "Failed to create API Key.": "API Anahtarı oluşturulamadı.", "Failed to read clipboard contents": "Pano içeriği okunamadı", - "February": "", + "February": "Şubat", "Feel free to add specific details": "Spesifik ayrıntılar eklemekten çekinmeyin", "File Mode": "Dosya Modu", "File not found.": "Dosya bulunamadı.", @@ -213,7 +213,7 @@ "Good Response": "İyi Yanıt", "has no conversations.": "hiç konuşması yok.", "Hello, {{name}}": "Merhaba, {{name}}", - "Help": "", + "Help": "Yardım", "Hide": "Gizle", "Hide Additional Params": "Ek Parametreleri Gizle", "How can I help you today?": "Bugün size nasıl yardımcı olabilirim?", @@ -227,14 +227,14 @@ "Import Modelfiles": "Model Dosyalarını İçe Aktar", "Import Prompts": "Promptları İçe Aktar", "Include `--api` flag when running stable-diffusion-webui": "stable-diffusion-webui çalıştırılırken `--api` bayrağını dahil edin", - "Input commands": "", + "Input commands": "Giriş komutları", "Interface": "Arayüz", - "Invalid Tag": "", - "January": "", + "Invalid Tag": "Geçersiz etiket", + "January": "Ocak", "join our Discord for help.": "yardım için Discord'umuza katılın.", "JSON": "JSON", - "July": "", - "June": "", + "July": "Temmuz", + "June": "Haziran", "JWT Expiration": "JWT Bitişi", "JWT Token": "JWT Token", "Keep Alive": "Canlı Tut", @@ -249,11 +249,11 @@ "Manage LiteLLM Models": "LiteLLM Modellerini Yönet", "Manage Models": "Modelleri Yönet", "Manage Ollama Models": "Ollama Modellerini Yönet", - "March": "", + "March": "Mart", "Max Tokens": "Maksimum Token", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Aynı anda en fazla 3 model indirilebilir. Lütfen daha sonra tekrar deneyin.", - "May": "", - "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "", + "May": "Mayıs", + "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "Bağlantınızı oluşturduktan sonra gönderdiğiniz mesajlar paylaşılmayacaktır. URL'ye sahip kullanıcılar paylaşılan sohbeti görüntüleyebilecektir.", "Minimum Score": "Minimum Skor", "Mirostat": "Mirostat", "Mirostat Eta": "Mirostat Eta", @@ -284,15 +284,15 @@ "Name your modelfile": "Model dosyanıza ad verin", "New Chat": "Yeni Sohbet", "New Password": "Yeni Parola", - "No results found": "", - "No source available": "", + "No results found": "Sonuç bulunamadı", + "No source available": "Kaynak mevcut değil", "Not factually correct": "Gerçeklere göre doğru değil", "Not sure what to add?": "Ne ekleyeceğinizden emin değil misiniz?", "Not sure what to write? Switch to": "Ne yazacağınızdan emin değil misiniz? Şuraya geçin", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Not: Minimum bir skor belirlerseniz, arama yalnızca minimum skora eşit veya daha yüksek bir skora sahip belgeleri getirecektir.", "Notifications": "Bildirimler", - "November": "", - "October": "", + "November": "Kasım", + "October": "Ekim", "Off": "Kapalı", "Okay, Let's Go!": "Tamam, Hadi Başlayalım!", "OLED Dark": "OLED Koyu", @@ -316,7 +316,7 @@ "OpenAI URL/Key required.": "OpenAI URL/Anahtar gereklidir.", "or": "veya", "Other": "Diğer", - "Overview": "", + "Overview": "Genel Bakış", "Parameters": "Parametreler", "Password": "Parola", "PDF document (.pdf)": "PDF belgesi (.pdf)", @@ -326,15 +326,15 @@ "Plain text (.txt)": "Düz metin (.txt)", "Playground": "Oyun Alanı", "Positive attitude": "Olumlu yaklaşım", - "Previous 30 days": "", - "Previous 7 days": "", + "Previous 30 days": "Önceki 30 gün", + "Previous 7 days": "Önceki 7 gün", "Profile Image": "Profil Fotoğrafı", - "Prompt": "", + "Prompt": "Prompt", "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Prompt (örn. Roma İmparatorluğu hakkında ilginç bir bilgi verin)", "Prompt Content": "Prompt İçeriği", "Prompt suggestions": "Prompt önerileri", "Prompts": "Promptlar", - "Pull \"{{searchValue}}\" from Ollama.com": "", + "Pull \"{{searchValue}}\" from Ollama.com": "Ollama.com'dan \"{{searchValue}}\" çekin", "Pull a model from Ollama.com": "Ollama.com'dan bir model çekin", "Pull Progress": "Çekme İlerlemesi", "Query Params": "Sorgu Parametreleri", @@ -347,12 +347,12 @@ "Regenerate": "Tekrar Oluştur", "Release Notes": "Sürüm Notları", "Remove": "Kaldır", - "Remove Model": "", - "Rename": "", + "Remove Model": "Modeli Kaldır", + "Rename": "Yeniden Adlandır", "Repeat Last N": "Son N'yi Tekrar Et", "Repeat Penalty": "Tekrar Cezası", "Request Mode": "İstek Modu", - "Reranking Model": "", + "Reranking Model": "Yeniden Sıralama Modeli", "Reranking model disabled": "Yeniden sıralama modeli devre dışı bırakıldı", "Reranking model set to \"{{reranking_model}}\"": "Yeniden sıralama modeli \"{{reranking_model}}\" olarak ayarlandı", "Reset Vector Storage": "Vektör Depolamayı Sıfırla", @@ -378,17 +378,17 @@ "Select a mode": "Bir mod seç", "Select a model": "Bir model seç", "Select an Ollama instance": "Bir Ollama örneği seçin", - "Select model": "", + "Select model": "Model seç", "Send a Message": "Bir Mesaj Gönder", "Send message": "Mesaj gönder", - "September": "", + "September": "Eylül", "Server connection verified": "Sunucu bağlantısı doğrulandı", "Set as default": "Varsayılan olarak ayarla", "Set Default Model": "Varsayılan Modeli Ayarla", - "Set embedding model (e.g. {{model}})": "", + "Set embedding model (e.g. {{model}})": "Gömme modelini ayarlayın (örn. {{model}})"", "Set Image Size": "Görüntü Boyutunu Ayarla", "Set Model": "Model Ayarla", - "Set reranking model (e.g. {{model}})": "", + "Set reranking model (e.g. {{model}})": "Yeniden sıralama modelini ayarlayın (örn. {{model}})", "Set Steps": "Adımları Ayarla", "Set Title Auto-Generation Model": "Otomatik Başlık Oluşturma Modelini Ayarla", "Set Voice": "Ses Ayarla", @@ -401,13 +401,13 @@ "Show": "Göster", "Show Additional Params": "Ek Parametreleri Göster", "Show shortcuts": "Kısayolları göster", - "Showcased creativity": "", + "Showcased creativity": "Sergilenen yaratıcılık", "sidebar": "kenar çubuğu", "Sign in": "Oturum aç", "Sign Out": "Çıkış Yap", "Sign up": "Kaydol", "Signing in": "Oturum açma", - "Source": "", + "Source": "Kaynak", "Speech recognition error: {{error}}": "Konuşma tanıma hatası: {{error}}", "Speech-to-Text Engine": "Konuşmadan Metne Motoru", "SpeechRecognition API is not supported in this browser.": "SpeechRecognition API bu tarayıcıda desteklenmiyor.", @@ -417,7 +417,7 @@ "Subtitle (e.g. about the Roman Empire)": "Alt başlık (örn. Roma İmparatorluğu hakkında)", "Success": "Başarılı", "Successfully updated.": "Başarıyla güncellendi.", - "Suggested": "", + "Suggested": "Önerilen", "Sync All": "Tümünü Senkronize Et", "System": "Sistem", "System Prompt": "Sistem Promptu", @@ -438,13 +438,13 @@ "Title": "Başlık", "Title (e.g. Tell me a fun fact)": "Başlık (e.g. Bana ilginç bir bilgi ver)", "Title Auto-Generation": "Otomatik Başlık Oluşturma", - "Title cannot be an empty string.": "", + "Title cannot be an empty string.": "Başlık boş bir dize olamaz.", "Title Generation Prompt": "Başlık Oluşturma Promptu", "to": "için", "To access the available model names for downloading,": "İndirilebilir mevcut model adlarına erişmek için,", "To access the GGUF models available for downloading,": "İndirilebilir mevcut GGUF modellerine erişmek için,", "to chat input.": "sohbet girişine.", - "Today": "", + "Today": "Bugün", "Toggle settings": "Ayarları Aç/Kapat", "Toggle sidebar": "Kenar Çubuğunu Aç/Kapat", "Top K": "Top K", @@ -473,8 +473,8 @@ "Version": "Sürüm", "Warning: If you update or change your embedding model, you will need to re-import all documents.": "Uyarı: Gömme modelinizi günceller veya değiştirirseniz, tüm belgeleri yeniden içe aktarmanız gerekecektir.", "Web": "Web", - "Web Loader Settings": "", - "Web Params": "", + "Web Loader Settings": "Web Yükleyici Ayarları", + "Web Params": "Web Parametreleri", "Webhook URL": "Webhook URL", "WebUI Add-ons": "WebUI Eklentileri", "WebUI Settings": "WebUI Ayarları", @@ -484,12 +484,12 @@ "Whisper (Local)": "Whisper (Yerel)", "Write a prompt suggestion (e.g. Who are you?)": "Bir prompt önerisi yazın (örn. Sen kimsin?)", "Write a summary in 50 words that summarizes [topic or keyword].": "[Konuyu veya anahtar kelimeyi] özetleyen 50 kelimelik bir özet yazın.", - "Yesterday": "", + "Yesterday": "Dün", "You": "Siz", - "You have no archived conversations.": "", - "You have shared this chat": "", + "You have no archived conversations.": "Arşivlenmiş sohbetleriniz yok.", + "You have shared this chat": "Bu sohbeti paylaştınız", "You're a helpful assistant.": "Sen yardımcı bir asistansın.", "You're now logged in.": "Şimdi oturum açtınız.", "Youtube": "Youtube", - "Youtube Loader Settings": "" + "Youtube Loader Settings": "Youtube Yükleyici Ayarları" } From 09357b6e81e9cda2aac744d4751f9c956a202334 Mon Sep 17 00:00:00 2001 From: aguvener <90110302+aguvener@users.noreply.github.com> Date: Sun, 12 May 2024 12:50:03 +0300 Subject: [PATCH 19/29] fix: update tr_TR translation with the latest updates. --- src/lib/i18n/locales/tr-TR/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index ff5a76140..5cab70790 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -385,7 +385,7 @@ "Server connection verified": "Sunucu bağlantısı doğrulandı", "Set as default": "Varsayılan olarak ayarla", "Set Default Model": "Varsayılan Modeli Ayarla", - "Set embedding model (e.g. {{model}})": "Gömme modelini ayarlayın (örn. {{model}})"", + "Set embedding model (e.g. {{model}})": "Gömme modelini ayarlayın (örn. {{model}})", "Set Image Size": "Görüntü Boyutunu Ayarla", "Set Model": "Model Ayarla", "Set reranking model (e.g. {{model}})": "Yeniden sıralama modelini ayarlayın (örn. {{model}})", From 5e5473c79266f69967d46c330954e6aaeb41c581 Mon Sep 17 00:00:00 2001 From: Simonas Date: Sun, 12 May 2024 15:13:41 +0200 Subject: [PATCH 20/29] Create and fill translation.json for Lithuanian --- src/lib/i18n/locales/lt-LT/translation.json | 495 ++++++++++++++++++++ 1 file changed, 495 insertions(+) create mode 100644 src/lib/i18n/locales/lt-LT/translation.json diff --git a/src/lib/i18n/locales/lt-LT/translation.json b/src/lib/i18n/locales/lt-LT/translation.json new file mode 100644 index 000000000..6eaf2b8d1 --- /dev/null +++ b/src/lib/i18n/locales/lt-LT/translation.json @@ -0,0 +1,495 @@ +{ + "'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' arba '-1' kad neišteitų iš galiojimo.", + "(Beta)": "(Beta)", + "(e.g. `sh webui.sh --api`)": "(pvz. `sh webui.sh --api`)", + "(latest)": "(naujausias)", + "{{modelName}} is thinking...": "{{modelName}} mąsto...", + "{{user}}'s Chats": "{{user}} susirašinėjimai", + "{{webUIName}} Backend Required": "{{webUIName}} būtinas serveris", + "a user": "naudotojas", + "About": "Apie", + "Account": "Paskyra", + "Accurate information": "Tiksli informacija", + "Add a model": "Pridėti modelį", + "Add a model tag name": "Pridėti žymą modeliui", + "Add a short description about what this modelfile does": "Pridėti trumpą šio dokumento aprašymą", + "Add a short title for this prompt": "Pridėti trumpą šios užklausos pavadinimą", + "Add a tag": "Pridėti žymą", + "Add custom prompt": "Pridėti užklausos šabloną", + "Add Docs": "Pridėti dokumentų", + "Add Files": "Pridėti failus", + "Add message": "Pridėti žinutę", + "Add Model": "Pridėti modelį", + "Add Tags": "Pridėti žymas", + "Add User": "Pridėti naudotoją", + "Adjusting these settings will apply changes universally to all users.": "Šių nustatymų pakeitimas bus pritakytas visiems naudotojams.", + "admin": "Administratorius", + "Admin Panel": "Administratorių panelė", + "Admin Settings": "Administratorių nustatymai", + "Advanced Parameters": "Gilieji nustatymai", + "all": "visi", + "All Documents": "Visi dokumentai", + "All Users": "Visi naudotojai", + "Allow": "Leisti", + "Allow Chat Deletion": "Leisti pokalbių ištrynimą", + "alphanumeric characters and hyphens": "skaičiai, raidės ir brūkšneliai", + "Already have an account?": "Ar jau turite paskyrą?", + "an assistant": "assistentas", + "and": "ir", + "and create a new shared link.": "sukurti naują dalinimosi nuorodą", + "API Base URL": "API basės nuoroda", + "API Key": "API raktas", + "API Key created.": "API raktas sukurtas", + "API keys": "API raktai", + "API RPM": "RPM API", + "April": "Balandis", + "Archive": "Archyvai", + "Archived Chats": "Archyvuoti pokalbiai", + "are allowed - Activate this command by typing": "leistina - aktyvuokite komandą rašydami", + "Are you sure?": "Are esate tikri?", + "Attach file": "Pridėti failą", + "Attention to detail": "Dėmesys detalėms", + "Audio": "Audio įrašas", + "August": "Rugpjūtis", + "Auto-playback response": "Automatinis atsakymo skaitymas", + "Auto-send input after 3 sec.": "Automatiškai išsiųsti įvestį po 3 sek.", + "AUTOMATIC1111 Base URL": "AUTOMATIC1111 bazės nuoroda", + "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 bazės nuoroda reikalinga.", + "available!": "prieinama!", + "Back": "Atgal", + "Bad Response": "Neteisingas atsakymas", + "before": "prieš", + "Being lazy": "Būvimas tingiu", + "Builder Mode": "Statytojo rėžimas", + "Bypass SSL verification for Websites": "Išvengti SSL patikros puslapiams", + "Cancel": "Atšaukti", + "Categories": "Kategorijos", + "Change Password": "Keisti slaptažodį", + "Chat": "Pokalbis", + "Chat History": "Pokalbių istorija", + "Chat History is off for this browser.": "Šioje naršyklėje pokalbių istorija išjungta.", + "Chats": "Pokalbiai", + "Check Again": "Patikrinti iš naujo", + "Check for updates": "Patikrinti atnaujinimus", + "Checking for updates...": "Ieškoma atnaujinimų...", + "Choose a model before saving...": "Pasirinkite modelį prieš išsaugant...", + "Chunk Overlap": "Blokų persidengimas", + "Chunk Params": "Blokų nustatymai", + "Chunk Size": "Blokų dydis", + "Citation": "Citata", + "Click here for help.": "Paspauskite čia dėl pagalbos.", + "Click here to": "Paspauskite čia, kad:", + "Click here to check other modelfiles.": "Paspauskite čia norėdami ieškoti modelių failų.", + "Click here to select": "Spauskite čia norėdami pasirinkti", + "Click here to select a csv file.": "Spauskite čia tam, kad pasirinkti csv failą", + "Click here to select documents.": "Spauskite čia norėdami pasirinkti dokumentus.", + "click here.": "paspauskite čia.", + "Click on the user role button to change a user's role.": "Paspauskite ant naudotojo rolės mygtuko tam, kad pakeisti naudotojo rolę.", + "Close": "Uždaryti", + "Collection": "Kolekcija", + "ComfyUI": "ComfyUI", + "ComfyUI Base URL": "ComfyUI bazės nuoroda", + "ComfyUI Base URL is required.": "ComfyUI bazės nuoroda privaloma", + "Command": "Command", + "Confirm Password": "Patvirtinkite slaptažodį", + "Connections": "Ryšiai", + "Content": "Turinys", + "Context Length": "Konteksto ilgis", + "Continue Response": "Tęsti atsakymą", + "Conversation Mode": "Pokalbio metodas", + "Copied shared chat URL to clipboard!": "Nukopijavote pokalbio nuorodą", + "Copy": "Kopijuoti", + "Copy last code block": "Kopijuoti paskutinį kodo bloką", + "Copy last response": "Kopijuoti paskutinį atsakymą", + "Copy Link": "Kopijuoti nuorodą", + "Copying to clipboard was successful!": "La copie dans le presse-papiers a réussi !", + "Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "Créez une phrase concise de 3-5 mots comme en-tête pour la requête suivante, en respectant strictement la limite de 3-5 mots et en évitant l'utilisation du mot 'titre' :", + "Create a modelfile": "Créer un fichier de modèle", + "Create Account": "Créer un compte", + "Create new key": "Sukurti naują raktą", + "Create new secret key": "Sukurti naują slaptą raktą", + "Created at": "Sukurta", + "Created At": "Sukurta", + "Current Model": "Dabartinis modelis", + "Current Password": "Esamas slaptažodis", + "Custom": "Personalizuota", + "Customize Ollama models for a specific purpose": "Personalizuoti Ollama modelius", + "Dark": "Tamsus", + "Dashboard": "Skydelis", + "Database": "Duomenų bazė", + "DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm", + "December": "Gruodis", + "Default": "Numatytasis", + "Default (Automatic1111)": "Numatytasis (Automatic1111)", + "Default (SentenceTransformers)": "Numatytasis (SentenceTransformers)", + "Default (Web API)": "Numatytasis (API Web)", + "Default model updated": "Numatytasis modelis atnaujintas", + "Default Prompt Suggestions": "Numatytieji užklausų pasiūlymai", + "Default User Role": "Numatytoji naudotojo rolė", + "delete": "ištrinti", + "Delete": "ištrinti", + "Delete a model": "Ištrinti modėlį", + "Delete chat": "Išrinti pokalbį", + "Delete Chat": "Ištrinti pokalbį", + "Delete Chats": "Ištrinti pokalbį", + "delete this link": "Ištrinti nuorodą", + "Delete User": "Ištrinti naudotoją", + "Deleted {{deleteModelTag}}": "{{deleteModelTag}} ištrinta", + "Deleted {{tagName}}": "{{tagName}} ištrinta", + "Description": "Aprašymas", + "Didn't fully follow instructions": "Pilnai nesekė instrukcijų", + "Disabled": "Neaktyvuota", + "Discover a modelfile": "Atrasti modelio failą", + "Discover a prompt": "Atrasti užklausas", + "Discover, download, and explore custom prompts": "Atrasti ir parsisiųsti užklausas", + "Discover, download, and explore model presets": "Atrasti ir parsisiųsti modelių konfigūracija", + "Display the username instead of You in the Chat": "Rodyti naudotojo vardą vietoje žodžio Jūs pokalbyje", + "Document": "Dokumentas", + "Document Settings": "Dokumento nuostatos", + "Documents": "Dokumentai", + "does not make any external connections, and your data stays securely on your locally hosted server.": "neturi jokių išorinių ryšių ir duomenys lieka serveryje.", + "Don't Allow": "Neleisti", + "Don't have an account?": "Neturite paskyros?", + "Don't like the style": "Nepatinka stilius", + "Download": "Parsisiųsti", + "Download canceled": "Parsisiuntimas atšauktas", + "Download Database": "Parsisiųsti duomenų bazę", + "Drop any files here to add to the conversation": "Įkelkite dokumentus čia, kad juos pridėti į pokalbį", + "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "pvz. '30s', '10m'. Laiko vienetai yra 's', 'm', 'h'.", + "Edit": "Redaguoti", + "Edit Doc": "Redaguoti dokumentą", + "Edit User": "Redaguoti naudotoją", + "Email": "El. paštas", + "Embedding Model": "Embedding modelis", + "Embedding Model Engine": "Embedding modelio variklis", + "Embedding model set to \"{{embedding_model}}\"": "Embedding modelis nustatytas kaip\"{{embedding_model}}\"", + "Enable Chat History": "Aktyvuoti pokalbių istoriją", + "Enable New Sign Ups": "Aktyvuoti naujas registracijas", + "Enabled": "Aktyvuota", + "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Įsitikinkite, kad CSV failas turi 4 kolonas šiuo eiliškumu: Name, Email, Password, Role.", + "Enter {{role}} message here": "Įveskite {{role}} žinutę čia", + "Enter Chunk Overlap": "Įveskite blokų persidengimą", + "Enter Chunk Size": "Įveskite blokų dydį", + "Enter Image Size (e.g. 512x512)": "Įveskite paveiksliuko dydį (pvz. 512x512)", + "Enter language codes": "Įveskite kalbos kodus", + "Enter LiteLLM API Base URL (litellm_params.api_base)": "Lite LLM API nuoroda (litellm_params.api_base)", + "Enter LiteLLM API Key (litellm_params.api_key)": "Lite LLM API raktas (litellm_params.api_key)", + "Enter LiteLLM API RPM (litellm_params.rpm)": "Lite LLM API RPM (litellm_params.rpm)", + "Enter LiteLLM Model (litellm_params.model)": "LiteLLM modelis (litellm_params.model)", + "Enter Max Tokens (litellm_params.max_tokens)": "Įveskite maksimalų žetonų skaičių (litellm_params.max_tokens)", + "Enter model tag (e.g. {{modelTag}})": "Įveskite modelio žymą (pvz. {{modelTag}})", + "Enter Number of Steps (e.g. 50)": "Įveskite žingsnių kiekį (pvz. 50)", + "Enter Score": "Įveskite rezultatą", + "Enter stop sequence": "Įveskite pabaigos sekvenciją", + "Enter Top K": "Įveskite Top K", + "Enter URL (e.g. http://127.0.0.1:7860/)": "Įveskite nuorodą (pvz. http://127.0.0.1:7860/)", + "Enter URL (e.g. http://localhost:11434)": "Įveskite nuorododą (pvz. http://localhost:11434", + "Enter Your Email": "Įveskite el. pašto adresą", + "Enter Your Full Name": "Įveskite vardą bei pavardę", + "Enter Your Password": "Įveskite slaptažodį", + "Enter Your Role": "Įveskite savo rolę", + "Experimental": "Eksperimentinis", + "Export All Chats (All Users)": "Eksportuoti visų naudotojų visus pokalbius", + "Export Chats": "Eksportuoti pokalbius", + "Export Documents Mapping": "Eksportuoti dokumentų žemėlapį", + "Export Modelfiles": "Eksportuoti modelių failus", + "Export Prompts": "Eksportuoti užklausas", + "Failed to create API Key.": "Nepavyko sukurti API rakto", + "Failed to read clipboard contents": "Nepavyko perskaityti kopijuoklės", + "February": "Vasaris", + "Feel free to add specific details": "Galite pridėti specifinių detalių", + "File Mode": "Dokumentų rėžimas", + "File not found.": "Failas nerastas.", + "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Nepavyko nsutatyti profilio nuotraukos", + "Fluidly stream large external response chunks": "Sklandžiai transliuoti ilgus atsakymus", + "Focus chat input": "Fokusuoti žinutės įvestį", + "Followed instructions perfectly": "Tobulai sekė instrukcijas", + "Format your variables using square brackets like this:": "Formatuokite kintamuosius su kvadratiniais skliausteliais:", + "From (Base Model)": "Iš (bazinis modelis)", + "Full Screen Mode": "Pilno ekrano rėžimas", + "General": "Bendri", + "General Settings": "Bendri nustatymai", + "Generation Info": "Generavimo informacija", + "Good Response": "Geras atsakymas", + "has no conversations.": "neturi pokalbių", + "Hello, {{name}}": "Sveiki, {{name}}", + "Help": "Pagalba", + "Hide": "Paslėpti", + "Hide Additional Params": "Pridėti papildomus parametrus", + "How can I help you today?": "Kuo galėčiau Jums padėti ?", + "Hybrid Search": "Hibridinė paieška", + "Image Generation (Experimental)": "Vaizdų generavimas (eksperimentinis)", + "Image Generation Engine": "Vaizdų generavimo variklis", + "Image Settings": "Vaizdų nustatymai", + "Images": "Vaizdai", + "Import Chats": "Importuoti pokalbius", + "Import Documents Mapping": "Importuoti dokumentų žemėlapį", + "Import Modelfiles": "Importuoti modelio failus", + "Import Prompts": "Importuoti užklausas", + "Include `--api` flag when running stable-diffusion-webui": "Pridėti `--api` kai vykdomas stable-diffusion-webui", + "Input commands": "Įvesties komandos", + "Interface": "Sąsaja", + "Invalid Tag": "Neteisinga žyma", + "January": "Sausis", + "join our Discord for help.": "prisijunkite prie mūsų Discord.", + "JSON": "JSON", + "July": "liepa", + "June": "birželis", + "JWT Expiration": "JWT išėjimas iš galiojimo", + "JWT Token": "JWT žetonas", + "Keep Alive": "Išlaikyti aktyviu", + "Keyboard shortcuts": "Klaviatūros trumpiniai", + "Language": "Kalba", + "Last Active": "Paskutinį kartą aktyvus", + "Light": "Šviesus", + "Listening...": "Klauso...", + "LLMs can make mistakes. Verify important information.": "Dideli kalbos modeliai gali klysti. Patikrinkite atsakymų teisingumą.", + "Made by OpenWebUI Community": "Sukurta OpenWebUI bendruomenės", + "Make sure to enclose them with": "Užtikrinktie, kad įtraukiate viduje:", + "Manage LiteLLM Models": "Tvarkyti LiteLLM modelus", + "Manage Models": "Tvarkyti modelius", + "Manage Ollama Models": "Tvarkyti Ollama modelius", + "March": "Kovas", + "Max Tokens": "Maksimalūs žetonai", + "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Daugiausiai trys modeliai gali būti parsisiunčiami vienu metu.", + "May": "gegužė", + "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "Žinutės, kurias siunčia po pasidalinimo nebus matomos nuorodos turėtojams.", + "Minimum Score": "Minimalus rezultatas", + "Mirostat": "Mirostat", + "Mirostat Eta": "Mirostat Eta", + "Mirostat Tau": "Mirostat Tau", + "MMMM DD, YYYY": "MMMM DD, YYYY", + "MMMM DD, YYYY HH:mm": "MMMM DD, YYYY HH:mm", + "Model '{{modelName}}' has been successfully downloaded.": "'{{modelName}}' modelis sėkmingai atsisiųstas.", + "Model '{{modelTag}}' is already in queue for downloading.": "Modelis '{{modelTag}}' jau atsisiuntimų eilėje.", + "Model {{modelId}} not found": "Modelis {{modelId}} nerastas", + "Model {{modelName}} already exists.": "Modelis {{modelName}} jau egzistuoja.", + "Model filesystem path detected. Model shortname is required for update, cannot continue.": "", + "Model Name": "Modelio pavadinimas", + "Model not selected": "Modelis nepasirinktas", + "Model Tag Name": "Modelio žymos pavadinimas", + "Model Whitelisting": "Modeliu baltasis sąrašas", + "Model(s) Whitelisted": "Modelis baltąjame sąraše", + "Modelfile": "Modelio failas", + "Modelfile Advanced Settings": "Pažengę nustatymai", + "Modelfile Content": "Modelio failo turinys", + "Modelfiles": "Modelio failai", + "Models": "Modeliai", + "More": "Daugiau", + "My Documents": "Mano dokumentai", + "My Modelfiles": "Mano modelių failai", + "My Prompts": "Mano užklausos", + "Name": "Pavadinimas", + "Name Tag": "Žymos pavadinimas", + "Name your modelfile": "Modelio failo pavadinimas", + "New Chat": "Naujas pokalbis", + "New Password": "Naujas slaptažodis", + "No results found": "Rezultatų nerasta", + "No source available": "Šaltinių nerasta", + "Not factually correct": "Faktiškai netikslu", + "Not sure what to add?": "Nežinote ką pridėti ?", + "Not sure what to write? Switch to": "Nežinoti ką rašyti ? Pakeiskite į", + "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Jei turite minimalų įvertį, paieška gražins tik tą informaciją, kuri viršyje šį įvertį", + "Notifications": "Pranešimai", + "November": "lapkritis", + "October": "spalis", + "Off": "Išjungta", + "Okay, Let's Go!": "Gerai, važiuojam!", + "OLED Dark": "OLED tamsus", + "Ollama": "Ollama", + "Ollama Base URL": "Ollama nuoroda", + "Ollama Version": "Ollama versija", + "On": "Aktyvuota", + "Only": "Tiktais", + "Only alphanumeric characters and hyphens are allowed in the command string.": "Leistinos tik raidės, skaičiai ir brūkšneliai.", + "Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "Jūsų failai vis dar tvarkomi.", + "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! Looks like the URL is invalid. Please double-check and try again.", + "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Naudojate nepalaikomą (front-end) web ui rėžimą. Prašau serviruokite WebUI iš back-end", + "Open": "Atverti", + "Open AI": "Open AI", + "Open AI (Dall-E)": "Open AI (Dall-E)", + "Open new chat": "Atverti naują pokalbį", + "OpenAI": "OpenAI", + "OpenAI API": "OpenAI API", + "OpenAI API Config": "Open AI API nustatymai", + "OpenAI API Key is required.": "OpenAI API raktas būtinas.", + "OpenAI URL/Key required.": "OpenAI API nuoroda ir raktas būtini", + "or": "arba", + "Other": "Kita", + "Overview": "Apžvalga", + "Parameters": "Nustatymai", + "Password": "Slaptažodis", + "PDF document (.pdf)": "PDF dokumentas (.pdf)", + "PDF Extract Images (OCR)": "PDF paveikslėlių skaitymas (OCR)", + "pending": "laukiama", + "Permission denied when accessing microphone: {{error}}": "Leidimas naudoti mikrofoną atmestas: {{error}}", + "Plain text (.txt)": "Grynas tekstas (.txt)", + "Playground": "Eksperimentavimo erdvė", + "Positive attitude": "Pozityvus elgesys", + "Previous 30 days": "Paskutinės 30 dienų", + "Previous 7 days": "Paskutinės 7 dienos", + "Profile Image": "Profilio nuotrauka", + "Prompt": "Užklausa", + "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Užklausa (pvz. supaprastink šį laišką)", + "Prompt Content": "Užklausos turinys", + "Prompt suggestions": "Užklausų pavyzdžiai", + "Prompts": "Užklausos", + "Pull \"{{searchValue}}\" from Ollama.com": "Rasti \"{{searchValue}}\" iš Ollama.com", + "Pull a model from Ollama.com": "Gauti modelį iš Ollama.com", + "Pull Progress": "Parsisintimo progresas", + "Query Params": "Užklausos parametrai", + "RAG Template": "RAG šablonas", + "Raw Format": "Grynasis formatas", + "Read Aloud": "Skaityti garsiai", + "Record voice": "Įrašyti balsą", + "Redirecting you to OpenWebUI Community": "Perkeliam Jus į OpenWebUI bendruomenę", + "Refused when it shouldn't have": "Atmesta kai neturėtų būti atmesta", + "Regenerate": "Generuoti iš naujo", + "Release Notes": "Naujovės", + "Remove": "Pašalinti", + "Remove Model": "Pašalinti modelį", + "Rename": "Pervadinti", + "Repeat Last N": "Pakartoti paskutinius N", + "Repeat Penalty": "Kartojimosi bauda", + "Request Mode": "Užklausos rėžimas", + "Reranking Model": "Reranking modelis", + "Reranking model disabled": "Reranking modelis neleidžiamas", + "Reranking model set to \"{{reranking_model}}\"": "Nustatytas rereanking modelis: \"{{reranking_model}}\"", + "Reset Vector Storage": "Reinicializuoti vektorių atmintį", + "Response AutoCopy to Clipboard": "Automatiškai nukopijuoti atsakymą", + "Role": "Rolė", + "Rosé Pine": "Rosé Pine", + "Rosé Pine Dawn": "Rosé Pine Dawn", + "Save": "Išsaugoti", + "Save & Create": "Išsaugoti ir sukurti", + "Save & Submit": "Išsaugoti ir pateikti", + "Save & Update": "Išsaugoti ir atnaujinti", + "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "Pokalbių saugojimas naršyklėje nebegalimas.", + "Scan": "Skenuoti", + "Scan complete!": "Skenavimas baigtas!", + "Scan for documents from {{path}}": "Skenuoti dokumentus iš {{path}}", + "Search": "Ieškoti", + "Search a model": "Ieškoti modelio", + "Search Documents": "Ieškoti dokumentų", + "Search Prompts": "Ieškoti užklausų", + "See readme.md for instructions": "Žiūrėti readme.md papildomoms instrukcijoms", + "See what's new": "Žiūrėti naujoves", + "Seed": "Sėkla", + "Select a mode": "Pasirinkti režimą", + "Select a model": "Pasirinkti modelį", + "Select an Ollama instance": "Pasirinkti Ollama instanciją", + "Select model": "Pasirinkti modelį", + "Send a Message": "Siųsti žinutę", + "Send message": "Siųsti žinutę", + "September": "rugsėjis", + "Server connection verified": "Serverio sujungimas patvirtintas", + "Set as default": "Nustatyti numatytąjį", + "Set Default Model": "Nustatyti numatytąjį modelį", + "Set embedding model (e.g. {{model}})": "Nustatyti embedding modelį", + "Set Image Size": "Nustatyti paveikslėlių dydį", + "Set Model": "Nustatyti modelį", + "Set reranking model (e.g. {{model}})": "Nustatyti reranking modelį", + "Set Steps": "Numatyti etapus", + "Set Title Auto-Generation Model": "Numatyti pavadinimų generavimo modelį", + "Set Voice": "Numatyti balsą", + "Settings": "Nustatymai", + "Settings saved successfully!": "Parametrai sėkmingai išsaugoti!", + "Share": "Dalintis", + "Share Chat": "Dalintis pokalbiu", + "Share to OpenWebUI Community": "Dalintis su OpenWebUI bendruomene", + "short-summary": "trumpinys", + "Show": "Rodyti", + "Show Additional Params": "Rodyti papildomus parametrus", + "Show shortcuts": "Rodyti trumpinius", + "Showcased creativity": "Kūrybingų užklausų paroda", + "sidebar": "šoninis meniu", + "Sign in": "Prisijungti", + "Sign Out": "Atsijungti", + "Sign up": "Sukurti paskyrą", + "Signing in": "Prisijungiama", + "Source": "Šaltinis", + "Speech recognition error: {{error}}": "Balso atpažinimo problema: {{error}}", + "Speech-to-Text Engine": "Balso atpažinimo modelis", + "SpeechRecognition API is not supported in this browser.": "Šioje naršyklėje negalimas balso atpažinimas.", + "Stop Sequence": "Baigt sekvenciją", + "STT Settings": "STT nustatymai", + "Submit": "Pateikti", + "Subtitle (e.g. about the Roman Empire)": "Subtitras", + "Success": "Sėkmingai", + "Successfully updated.": "Sėkmingai atnaujinta.", + "Suggested": "Siūloma", + "Sync All": "Viską sinhronizuoti", + "System": "Sistema", + "System Prompt": "Sistemos užklausa", + "Tags": "Žymos", + "Tell us more:": "Papasakokite daugiau", + "Temperature": "Temperatūra", + "Template": "Modelis", + "Text Completion": "Teksto pildymas", + "Text-to-Speech Engine": "Balso sintezės modelis", + "Tfs Z": "Tfs Z", + "Thanks for your feedback!": "Ačiū už atsiliepimus", + "The score should be a value between 0.0 (0%) and 1.0 (100%).": "Rezultatas turėtų būti tarp 0.0 (0%) ir 1.0 (100%)", + "Theme": "Tema", + "This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Tai užtikrina, kad Jūsų pokalbiai saugiai saugojami duomenų bazėje. Ačiū!", + "This setting does not sync across browsers or devices.": "Šis parametras nesisinchronizuoja su skirtingomis naršyklėmis ir įrankiais.", + "Thorough explanation": "Platus paaiškinimas", + "Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "Jei norite pakeisti keletą kintamųjų vieną po kitos, spauskite Tab", + "Title": "Pavadinimas", + "Title (e.g. Tell me a fun fact)": "Pavadinimas", + "Title Auto-Generation": "Automatinis pavadinimų generavimas", + "Title cannot be an empty string.": "Pavadinimas negali būti tuščias", + "Title Generation Prompt": "Pavadinimo generavimo užklausa", + "to": "kam", + "To access the available model names for downloading,": "Tam, kad prieiti prie galimų parsisiųsti modelių", + "To access the GGUF models available for downloading,": "Tam, kad prieiti prie galimų parsisiųsti GGUF,", + "to chat input.": "į pokalbio įvestį", + "Today": "Šiandien", + "Toggle settings": "Atverti/užverti parametrus", + "Toggle sidebar": "Atverti/užverti šoninį meniu", + "Top K": "Top K", + "Top P": "Top P", + "Trouble accessing Ollama?": "Problemos prieinant prie Ollama?", + "TTS Settings": "TTS parametrai", + "Type Hugging Face Resolve (Download) URL": "Įveskite Hugging Face Resolve nuorodą", + "Uh-oh! There was an issue connecting to {{provider}}.": "O ne! Prisijungiant prie {{provider}} kilo problema.", + "Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Nepažįstamas '{{file_type}}' failo formatas, tačiau jis priimtas ir bus apdorotas kaip grynas tekstas", + "Update and Copy Link": "Atnaujinti ir kopijuoti nuorodą", + "Update password": "Atnaujinti slaptažodį", + "Upload a GGUF model": "Parsisiųsti GGUF modelį", + "Upload files": "Įkelti failus", + "Upload Progress": "Įkėlimo progresas", + "URL Mode": "URL režimas", + "Use '#' in the prompt input to load and select your documents.": "Naudokite '#' norėdami naudoti dokumentą.", + "Use Gravatar": "Naudoti Gravatar", + "Use Initials": "Naudotojo inicialai", + "user": "naudotojas", + "User Permissions": "Naudotojo leidimai", + "Users": "Naudotojai", + "Utilize": "Naudoti", + "Valid time units:": "Teisingūs laiko vienetai :", + "variable": "kintamasis", + "variable to have them replaced with clipboard content.": "kintamoji pakeičiama kopijuoklės turiniu.", + "Version": "Versija", + "Warning: If you update or change your embedding model, you will need to re-import all documents.": "Jei pakeisite embedding modelį, turėsite reimportuoti visus dokumentus", + "Web": "Web", + "Web Loader Settings": "Web krovimo nustatymai", + "Web Params": "Web nustatymai", + "Webhook URL": "Webhook nuoroda", + "WebUI Add-ons": "WebUI priedai", + "WebUI Settings": "WebUI parametrai", + "WebUI will make requests to": "WebUI vykdys užklausas", + "What’s New in": "Kas naujo", + "When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Kai istorija išjungta, pokalbiai neatsiras jūsų istorijoje.", + "Whisper (Local)": "Whisper (lokalus)", + "Write a prompt suggestion (e.g. Who are you?)": "Parašykite užklausą", + "Write a summary in 50 words that summarizes [topic or keyword].": "Parašyk santrumpą trumpesnę nei 50 žodžių šiam tekstui: [tekstas]", + "Yesterday": "Vakar", + "You": "Jūs", + "You have no archived conversations.": "Jūs neturite archyvuotų pokalbių", + "You have shared this chat": "Pasidalinote šiuo pokalbiu", + "You're a helpful assistant.": "Esi asistentas.", + "You're now logged in.": "Esate prisijungę.", + "Youtube": "Youtube", + "Youtube Loader Settings": "Youtube krovimo nustatymai" +} From 6671e5f17083552f000f9ca69d41e4ab9a7d0cd6 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Sun, 12 May 2024 14:05:38 -0400 Subject: [PATCH 21/29] chore: add HTTP-Referer and X-Title headers for Open WebUI --- backend/apps/openai/main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/apps/openai/main.py b/backend/apps/openai/main.py index b5d1e68d6..e346fc860 100644 --- a/backend/apps/openai/main.py +++ b/backend/apps/openai/main.py @@ -116,6 +116,8 @@ async def speech(request: Request, user=Depends(get_verified_user)): headers = {} headers["Authorization"] = f"Bearer {app.state.OPENAI_API_KEYS[idx]}" headers["Content-Type"] = "application/json" + headers['HTTP-Referer'] = "https://openwebui.com/" + headers['X-Title'] = "Open WebUI" r = None try: From bd823346478772087772d574229acf93a8bb77cd Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Mon, 13 May 2024 08:28:24 -0400 Subject: [PATCH 22/29] chore: add additional headers only for Openrouter --- backend/apps/openai/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/apps/openai/main.py b/backend/apps/openai/main.py index e346fc860..b38c2bc2d 100644 --- a/backend/apps/openai/main.py +++ b/backend/apps/openai/main.py @@ -116,9 +116,9 @@ async def speech(request: Request, user=Depends(get_verified_user)): headers = {} headers["Authorization"] = f"Bearer {app.state.OPENAI_API_KEYS[idx]}" headers["Content-Type"] = "application/json" - headers['HTTP-Referer'] = "https://openwebui.com/" - headers['X-Title'] = "Open WebUI" - + if "openrouter.ai" in app.state.OPENAI_API_BASE_URLS[idx]: + headers['HTTP-Referer'] = "https://openwebui.com/" + headers['X-Title'] = "Open WebUI" r = None try: r = requests.post( From df167d87855f8b5e7bddc32ef3c3cd489027c7e1 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 13 May 2024 18:00:30 +0300 Subject: [PATCH 23/29] fix: load i18n for /error page --- src/lib/i18n/index.ts | 2 +- src/routes/+layout.svelte | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/lib/i18n/index.ts b/src/lib/i18n/index.ts index b0580345f..172c42f91 100644 --- a/src/lib/i18n/index.ts +++ b/src/lib/i18n/index.ts @@ -37,7 +37,7 @@ const createIsLoadingStore = (i18n: i18nType) => { return isLoading; }; -export const initI18n = (defaultLocale: string) => { +export const initI18n = (defaultLocale: string | undefined) => { let detectionOrder = defaultLocale ? ['querystring', 'localStorage'] : ['querystring', 'localStorage', 'navigator']; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index db43a0312..5a8a8bba3 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -21,20 +21,22 @@ onMount(async () => { theme.set(localStorage.theme); - // Check Backend Status - const backendConfig = await getBackendConfig(); + let backendConfig = null; + try { + backendConfig = await getBackendConfig(); + console.log("Backend config:", backendConfig); + } catch (error) { + console.error("Error loading backend config:", error); + } + // Initialize i18n even if we didn't get a backend config, + // so `/error` can show something that's not `undefined`. + initI18n(backendConfig?.default_locale); if (backendConfig) { // Save Backend Status to Store await config.set(backendConfig); - if ($config.default_locale) { - initI18n($config.default_locale); - } else { - initI18n(); - } await WEBUI_NAME.set(backendConfig.name); - console.log(backendConfig); if ($config) { if (localStorage.token) { From b5c759a059280da3849eaf48100be9738acef5a8 Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Mon, 13 May 2024 10:56:30 -1000 Subject: [PATCH 24/29] chore: format --- src/lib/i18n/locales/he-IL/translation.json | 1110 ++++++++----------- 1 file changed, 493 insertions(+), 617 deletions(-) diff --git a/src/lib/i18n/locales/he-IL/translation.json b/src/lib/i18n/locales/he-IL/translation.json index f2f96ced0..cf2f26bf4 100644 --- a/src/lib/i18n/locales/he-IL/translation.json +++ b/src/lib/i18n/locales/he-IL/translation.json @@ -1,619 +1,495 @@ { - "'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' או '-1' ללא תפוגה.", - "(Beta)": "(בטא)", - "(e.g. `sh webui.sh --api`)": "(למשל `sh webui.sh --api`)", - "(latest)": "(האחרון)", - "{{modelName}} is thinking...": "{{modelName}} חושב...", - "{{user}}'s Chats": "צ'אטים של {{user}}", - "{{webUIName}} Backend Required": "נדרש Backend של {{webUIName}}", - "a user": "משתמש", - "About": "אודות", - "Account": "חשבון", - "Accurate information": "מידע מדויק", - "Add a model": "הוסף מודל", - "Add a model tag name": "הוסף שם תג למודל", - "Add a short description about what this modelfile does": "הוסף תיאור קצר על מה שהקובץ מודל עושה", - "Add a short title for this prompt": "הוסף כותרת קצרה לפקודה זו", - "Add a tag": "הוסף תג", - "Add custom prompt": "הוסף פקודה מותאמת אישית", - "Add Docs": "הוסף מסמכים", - "Add Files": "הוסף קבצים", - "Add message": "הוסף הודעה", - "Add Model": "הוסף מודל", - "Add Tags": "הוסף תגים", - "Add User": "הוסף משתמש", - "Adjusting these settings will apply changes universally to all users.": "התאמת הגדרות אלו תחול על כל המשתמשים.", - "admin": "מנהל", - "Admin Panel": "לוח בקרה למנהל", - "Admin Settings": "הגדרות מנהל", - "Advanced Parameters": "פרמטרים מתקדמים", - "all": "הכל", - "All Documents": "כל המסמכים", - "All Users": "כל המשתמשים", - "Allow": "אפשר", - "Allow Chat Deletion": "אפשר מחיקת צ'אט", - "alphanumeric characters and hyphens": "תווים אלפאנומריים ומקפים", - "Already have an account?": "כבר יש לך חשבון?", - "an assistant": "עוזר", - "and": "וגם", - "and create a new shared link.": "וצור קישור משותף חדש.", - "API Base URL": "כתובת URL בסיסית ל-API", - "API Key": "מפתח API", - "API Key created.": "מפתח API נוצר.", - "API keys": "מפתחות API", - "API RPM": "RPM של API", - "April": "אפריל", - "Archive": "ארכיון", - "Archived Chats": "צ'אטים מאורכבים", - "are allowed - Activate this command by typing": "מותרים - הפעל פקודה זו על ידי הקלדה", - "Are you sure?": "האם אתה בטוח?", - "Attach file": "צרף קובץ", - "Attention to detail": "תשומת לב לפרטים", - "Audio": "אודיו", - "August": "אוגוסט", - "Auto-playback response": "תגובת השמעה אוטומטית", - "Auto-send input after 3 sec.": "שליחת קלט אוטומטית אחרי 3 שניות", - "AUTOMATIC1111 Base URL": "כתובת URL בסיסית של AUTOMATIC1111", - "AUTOMATIC1111 Base URL is required.": "נדרשת כתובת URL בסיסית של AUTOMATIC1111", - "available!": "זמין!", - "Back": "חזור", - "Bad Response": "תגובה שגויה", - "before": "לפני", - "Being lazy": "להיות עצלן", - "Builder Mode": "מצב בונה", - "Bypass SSL verification for Websites": "עקוף אימות SSL עבור אתרים", - "Cancel": "בטל", - "Categories": "קטגוריות", - "Change Password": "שנה סיסמה", - "Chat": "צ'אט", - "Chat History": "היסטוריית צ'אט", - "Chat History is off for this browser.": "היסטוריית הצ'אט כבויה לדפדפן זה.", - "Chats": "צ'אטים", - "Check Again": "בדוק שוב", - "Check for updates": "בדוק עדכונים", - "Checking for updates...": "בודק עדכונים...", - "Choose a model before saving...": "בחר מודל לפני השמירה...", - "Chunk Overlap": "חפיפת נתונים", - "Chunk Params": "פרמטרי נתונים", - "Chunk Size": "גודל נתונים", - "Citation": "ציטוט", - "Click here for help.": "לחץ כאן לעזרה.", - "Click here to": "לחץ כאן כדי", - "Click here to check other modelfiles.": "לחץ כאן לבדיקת קבצי מודלים אחרים.", - "Click here to select": "לחץ כאן לבחירה", - "Click here to select a csv file.": "לחץ כאן לבחירת קובץ csv.", - "Click here to select documents.": "לחץ כאן לבחירת מסמכים.", - "click here.": "לחץ כאן.", - "Click on the user role button to change a user's role.": "לחץ על כפתור תפקיד המשתמש כדי לשנות את תפקיד המשתמש.", - "Close": "סגור", - "Collection": "אוסף", - "ComfyUI": "ComfyUI", - "ComfyUI Base URL": "כתובת URL בסיסית של ComfyUI", - "ComfyUI Base URL is required.": "נדרשת כתובת URL בסיסית של ComfyUI", - "Command": "פקודה", - "Confirm Password": "אשר סיסמה", - "Connections": "חיבורים", - "Content": "תוכן", - "Context Length": "אורך הקשר", - "Continue Response": "המשך תגובה", - "Conversation Mode": "מצב שיחה", - "Copied shared chat URL to clipboard!": "העתקת כתובת URL של צ'אט משותף ללוח!", - "Copy": "העתק", - "Copy last code block": "העתק את בלוק הקוד האחרון", - "Copy last response": "העתק את התגובה האחרונה", - "Copy Link": "העתק קישור", - "Copying to clipboard was successful!": "ההעתקה ללוח הייתה מוצלחת!", - "Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "צור ביטוי תמציתי של 3-5 מילים ככותרת לשאילתה הבאה, תוך שמירה מדויקת על מגבלת 3-5 המילים והימנעות משימוש במילה 'כותרת':", - "Create a modelfile": "צור קובץ מודל", - "Create Account": "צור חשבון", - "Create new key": "צור מפתח חדש", - "Create new secret key": "צור מפתח סודי חדש", - "Created at": "נוצר ב", - "Created At": "נוצר ב", - "Current Model": "המודל הנוכחי", - "Current Password": "הסיסמה הנוכחית", - "Custom": "מותאם אישית", - "Customize Ollama models for a specific purpose": "התאמה אישית של מודלים של Ollama למטרה מסוימת", - "Dark": "כהה", - "Dashboard": "לוח בקרה", - "Database": "מסד נתונים", - "DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm", - "December": "דצמבר", - "Default": "ברירת מחדל", - "Default (Automatic1111)": "ברירת מחדל (Automatic1111)", - "Default (SentenceTransformers)": "ברירת מחדל (SentenceTransformers)", - "Default (Web API)": "ברירת מחדל (Web API)", - "Default model updated": "המודל המוגדר כברירת מחדל עודכן", - "Default Prompt Suggestions": "הצעות ברירת מחדל לפקודות", - "Default User Role": "תפקיד משתמש ברירת מחדל", - "delete": "מחק", - "Delete": "מחק", - "Delete a model": "מחק מודל", - "Delete chat": "מחק צ'אט", - "Delete Chat": "מחק צ'אט", - "Delete Chats": "מחק צ'אטים", - "delete this link": "מחק את הקישור הזה", - "Delete User": "מחק משתמש", - "Deleted {{deleteModelTag}}": "נמחק {{deleteModelTag}}", - "Deleted {{tagName}}": "נמחק {{tagName}}", - "Description": "תיאור", - "Didn't fully follow instructions": "לא עקב אחרי ההוראות באופן מלא", - "Disabled": "מושבת", - "Discover a modelfile": "גלה קובץ מודל", - "Discover a prompt": "גלה פקודה", - "Discover, download, and explore custom prompts": "גלה, הורד, וחקור פקודות מותאמות אישית", - "Discover, download, and explore model presets": "גלה, הורד, וחקור הגדרות מודל מוגדרות מראש", - "Display the username instead of You in the Chat": "הצג את שם המשתמש במקום 'אתה' בצ'אט", - "Document": "מסמך", - "Document Settings": "הגדרות מסמך", - "Documents": "מסמכים", - "does not make any external connections, and your data stays securely on your locally hosted server.": "לא מבצע חיבורים חיצוניים, והנתונים שלך נשמרים באופן מאובטח בשרת המקומי שלך.", - "Don't Allow": "אל תאפשר", - "Don't have an account?": "אין לך חשבון?", - "Don't like the style": "לא אוהב את הסגנון", - "Download": "הורד", - "Download canceled": "ההורדה בוטלה", - "Download Database": "הורד מסד נתונים", - "Drop any files here to add to the conversation": "גרור כל קובץ לכאן כדי להוסיף לשיחה", - "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "למשל '30s', '10m'. יחידות זמן חוקיות הן 's', 'm', 'h'.", - "Edit": "ערוך", - "Edit Doc": "ערוך מסמך", - "Edit User": "ערוך משתמש", - "Email": "דוא\"ל", - "Embedding Model": "מודל הטמעה", - "Embedding Model Engine": "מנוע מודל הטמעה", - "Embedding model set to \"{{embedding_model}}\"": "מודל ההטמעה הוגדר ל-\"{{embedding_model}}\"", - "Enable Chat History": "הפעל היסטוריית צ'אט", - "Enable New Sign Ups": "אפשר הרשמות חדשות", - "Enabled": "מופעל", - "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "ודא שקובץ ה-CSV שלך כולל 4 עמודות בסדר הבא: שם, דוא\"ל, סיסמה, תפקיד.", - "Enter {{role}} message here": "הזן הודעת {{role}} כאן", - "Enter Chunk Overlap": "הזן חפיפת נתונים", - "Enter Chunk Size": "הזן גודל נתונים", - "Enter Image Size (e.g. 512x512)": "הזן גודל תמונה (למשל 512x512)", - "Enter language codes": "הזן קודי שפה", - "Enter LiteLLM API Base URL (litellm_params.api_base)": "הזן כתובת URL בסיסית ל-API של LiteLLM (litellm_params.api_base)", - "Enter LiteLLM API Key (litellm_params.api_key)": "הזן מפתח API של LiteLLM (litellm_params.api_key)", - "Enter LiteLLM API RPM (litellm_params.rpm)": "הזן RPM של API של LiteLLM (litellm_params.rpm)", - "Enter LiteLLM Model (litellm_params.model)": "הזן מודל LiteLLM (litellm_params.model)", - "Enter Max Tokens (litellm_params.max_tokens)": "הזן מספר מקסימלי של טוקנים (litellm_params.max_tokens)", - "Enter model tag (e.g. {{modelTag}})": "הזן תג מודל (למשל {{modelTag}})", - "Enter Number of Steps (e.g. 50)": "הזן מספר שלבים (למשל 50)", - "Enter Score": "הזן ציון", - "Enter stop sequence": "הזן רצף עצירה", - "Enter Top K": "הזן Top K", - "Enter URL (e.g. http://127.0.0.1:7860/)": "הזן כתובת URL (למשל http://127.0.0.1:7860/)", - "Enter URL (e.g. http://localhost:11434)": "הזן כתובת URL (למשל http://localhost:11434)", - "Enter Your Email": "הזן את דוא\"ל שלך", - "Enter Your Full Name": "הזן את שמך המלא", - "Enter Your Password": "הזן את הסיסמה שלך", - "Enter Your Role": "הזן את התפקיד שלך", - "Experimental": "ניסיוני", - "Export All Chats (All Users)": "ייצוא כל הצ'אטים (כל המשתמשים)", - "Export Chats": "ייצוא צ'אטים", - "Export Documents Mapping": "ייצוא מיפוי מסמכים", - "Export Modelfiles": "ייצוא קבצי מודלים", - "Export Prompts": "ייצוא פקודות", - "Failed to create API Key.": "יצירת מפתח API נכשלה.", - "Failed to read clipboard contents": "קריאת תוכן הלוח נכשלה", - "February": "פברואר", - "Feel free to add specific details": "נא להוסיף פרטים ספציפיים לפי רצון", - "File Mode": "מצב קובץ", - "File not found.": "הקובץ לא נמצא.", - "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "התגלתה הזיית טביעת אצבע: לא ניתן להשתמש בראשי תיבות כאווטאר. משתמש בתמונת פרופיל ברירת מחדל.", - "Fluidly stream large external response chunks": "שידור נתונים חיצוניים בקצב רציף", - "Focus chat input": "מיקוד הקלט לצ'אט", - "Followed instructions perfectly": "עקב אחר ההוראות במושלמות", - "Format your variables using square brackets like this:": "עצב את המשתנים שלך באמצעות סוגריים מרובעים כך:", - "From (Base Model)": "מ (מודל בסיס)", - "Full Screen Mode": "מצב מסך מלא", - "General": "כללי", - "General Settings": "הגדרות כלליות", - "Generation Info": "מידע על היצירה", - "Good Response": "תגובה טובה", - "has no conversations.": "אין שיחות.", - "Hello, {{name}}": "שלום, {{name}}", - "Help": "עזרה", - "Hide": "הסתר", - "Hide Additional Params": "הסתר פרמטרים נוספים", - "How can I help you today?": "כיצד אוכל לעזור לך היום?", - "Hybrid Search": "חיפוש היברידי", - "Image Generation (Experimental)": "יצירת תמונות (ניסיוני)", - "Image Generation Engine": "מנוע יצירת תמונות", - "Image Settings": "הגדרות תמונה", - "Images": "תמונות", - "Import Chats": "יבוא צ'אטים", - "Import Documents Mapping": "יבוא מיפוי מסמכים", - "Import Modelfiles": "יבוא קבצי מודלים", - "Import Prompts": "יבוא פקודות", - "Include `--api` flag when running stable-diffusion-webui": "כלול את הדגל `--api` בעת הרצת stable-diffusion-webui", - "Input commands": "פקודות קלט", - "Interface": "ממשק", - "Invalid Tag": "תג לא חוקי", - "January": "ינואר", - "join our Discord for help.": "הצטרף ל-Discord שלנו לעזרה.", - "JSON": "JSON", - "July": "יולי", - "June": "יוני", - "JWT Expiration": "תפוגת JWT", - "JWT Token": "אסימון JWT", - "Keep Alive": "השאר פעיל", - "Keyboard shortcuts": "קיצורי מקלדת", - "Language": "שפה", - "Last Active": "פעיל לאחרונה", - "Light": "בהיר", - "Listening...": "מאזין...", - "LLMs can make mistakes. Verify important information.": "מודלים בשפה טבעית יכולים לטעות. אמת מידע חשוב.", - "Made by OpenWebUI Community": "נוצר על ידי קהילת OpenWebUI", - "Make sure to enclose them with": "ודא להקיף אותם עם", - "Manage LiteLLM Models": "נהל מודלים של LiteLLM", - "Manage Models": "נהל מודלים", - "Manage Ollama Models": "נהל מודלים של Ollama", - "March": "מרץ", - "Max Tokens": "מקסימום טוקנים", - "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "ניתן להוריד מקסימום 3 מודלים בו זמנית. אנא נסה שוב מאוחר יותר.", - "May": "מאי", - "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "הודעות שתשלח לאחר יצירת הקישור שלך לא ישותפו. משתמשים עם הכתובת URL יוכלו לצפות בצ'אט המשותף.", - "Minimum Score": "ציון מינימלי", - "Mirostat": "Mirostat", - "Mirostat Eta": "Mirostat Eta", - "Mirostat Tau": "Mirostat Tau", - "MMMM DD, YYYY": "DD בMMMM, YYYY", - "MMMM DD, YYYY HH:mm": "DD בMMMM, YYYY HH:mm", - "Model '{{modelName}}' has been successfully downloaded.": "המודל '{{modelName}}' הורד בהצלחה.", - "Model '{{modelTag}}' is already in queue for downloading.": "המודל '{{modelTag}}' כבר בתור להורדה.", - "Model {{modelId}} not found": "המודל {{modelId}} לא נמצא", - "Model {{modelName}} already exists.": "המודל {{modelName}} כבר קיים.", - "Model filesystem path detected. Model shortname is required for update, cannot continue.": "נתיב מערכת הקבצים של המודל זוהה. נדרש שם קצר של המודל לעדכון, לא ניתן להמשיך.", - "Model Name": "שם המודל", - "Model not selected": "לא נבחר מודל", - "Model Tag Name": "שם תג המודל", - "Model Whitelisting": "רישום לבן של מודלים", - "Model(s) Whitelisted": "מודלים שנכללו ברשימה הלבנה", - "Modelfile": "קובץ מודל", - "Modelfile Advanced Settings": "הגדרות מתקדמות לקובץ מודל", - "Modelfile Content": "תוכן קובץ מודל", - "Modelfiles": "קבצי מודל", - "Models": "מודלים", - "More": "עוד", - "My Documents": "המסמכים שלי", - "My Modelfiles": "קבצי המודל שלי", - "My Prompts": "הפקודות שלי", - "Name": "שם", - "Name Tag": "תג שם", - "Name your modelfile": "תן שם לקובץ המודל שלך", - "New Chat": "צ'אט חדש", - "New Password": "סיסמה חדשה", - "No results found": "לא נמצאו תוצאות", - "No source available": "אין מקור זמין", - "Not factually correct": "לא נכון מבחינה עובדתית", - "Not sure what to add?": "לא בטוח מה להוסיף?", - "Not sure what to write? Switch to": "לא בטוח מה לכתוב? החלף ל", - "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "הערה: אם תקבע ציון מינימלי, החיפוש יחזיר רק מסמכים עם ציון שגבוה או שווה לציון המינימלי.", - "Notifications": "התראות", - "November": "נובמבר", - "October": "אוקטובר", - "Off": "כבוי", - "Okay, Let's Go!": "בסדר, בואו נתחיל!", - "OLED Dark": "OLED כהה", - "Ollama": "Ollama", - "Ollama Base URL": "כתובת URL בסיסית של Ollama", - "Ollama Version": "גרסת Ollama", - "On": "פועל", - "Only": "רק", - "Only alphanumeric characters and hyphens are allowed in the command string.": "רק תווים אלפאנומריים ומקפים מותרים במחרוזת הפקודה.", - "Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "אופס! תחזיק מעמד! הקבצים שלך עדיין בתהליך העיבוד. אנו מבשלים אותם לשלמות. נא להתאזר בסבלנות ונודיע לך ברגע שיהיו מוכנים.", - "Oops! Looks like the URL is invalid. Please double-check and try again.": "אופס! נראה שהכתובת URL אינה תקינה. אנא בדוק שוב ונסה שנית.", - "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "אופס! אתה משתמש בשיטה לא נתמכת (רק חזית). אנא שרת את ממשק המשתמש האינטרנטי מהשרת האחורי.", - "Open": "פתח", - "Open AI": "Open AI", - "Open AI (Dall-E)": "Open AI (Dall-E)", - "Open new chat": "פתח צ'אט חדש", - "OpenAI": "OpenAI", - "OpenAI API": "API של OpenAI", - "OpenAI API Config": "תצורת API של OpenAI", - "OpenAI API Key is required.": "נדרש מפתח API של OpenAI.", - "OpenAI URL/Key required.": "נדרשת כתובת URL/מפתח של OpenAI.", - "or": "או", - "Other": "אחר", - "Overview": "סקירה כללית", - "Parameters": "פרמטרים", - "Password": "סיסמה", - "PDF document (.pdf)": "מסמך PDF (.pdf)", - "PDF Extract Images (OCR)": "חילוץ תמונות מ-PDF (OCR)", - "pending": "ממתין", - "Permission denied when accessing microphone: {{error}}": "ההרשאה נדחתה בעת גישה למיקרופון: {{error}}", - "Plain text (.txt)": "טקסט פשוט (.txt)", - "Playground": "אזור משחקים", - "Positive attitude": "גישה חיובית", - "Previous 30 days": "30 הימים הקודמים", - "Previous 7 days": "7 הימים הקודמים", - "Profile Image": "תמונת פרופיל", - "Prompt": "פקודה", - "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "פקודה (למשל, ספר לי עובדה מעניינת על האימפריה הרומית)", - "Prompt Content": "תוכן הפקודה", - "Prompt suggestions": "הצעות לפקודות", - "Prompts": "פקודות", - "Pull \"{{searchValue}}\" from Ollama.com": "משוך \"{{searchValue}}\" מ-Ollama.com", - "Pull a model from Ollama.com": "משוך מודל מ-Ollama.com", - "Pull Progress": "משוך התקדמות", - "Query Params": "פרמטרי שאילתה", - "RAG Template": "תבנית RAG", - "Raw Format": "פורמט גולמי", - "Read Aloud": "קרא בקול", - "Record voice": "הקלט קול", - "Redirecting you to OpenWebUI Community": "מפנה אותך לקהילת OpenWebUI", - "Refused when it shouldn't have": "נדחה כאשר לא היה צריך", - "Regenerate": "הפק מחדש", - "Release Notes": "הערות שחרור", - "Remove": "הסר", - "Remove Model": "הסר מודל", - "Rename": "שנה שם", - "Repeat Last N": "חזור על ה-N האחרונים", - "Repeat Penalty": "עונש חזרה", - "Request Mode": "מצב בקשה", - "Reranking Model": "מודל דירוג מחדש", - "Reranking model disabled": "מודל דירוג מחדש מושבת", - "Reranking model set to \"{{reranking_model}}\"": "מודל דירוג מחדש הוגדר ל-\"{{reranking_model}}\"", - "Reset Vector Storage": "איפוס אחסון וקטורים", - "Response AutoCopy to Clipboard": "העתקה אוטומטית של תגובה ללוח", - "Role": "תפקיד", - "Rosé Pine": "Rosé Pine", - "Rosé Pine Dawn": "Rosé Pine Dawn", - "Save": "שמור", - "Save & Create": "שמור וצור", - "Save & Submit": "שמור ושלח", - "Save & Update": "שמור ועדכן", - "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "שמירת יומני צ'אט ישירות באחסון הדפדפן שלך אינה נתמכת יותר. אנא הקדש רגע להוריד ולמחוק את יומני הצ'אט שלך על ידי לחיצה על הכפתור למטה. אל דאגה, באפשרותך לייבא מחדש בקלות את יומני הצ'אט שלך לשרת האחורי דרך", - "Scan": "סרוק", - "Scan complete!": "הסריקה הושלמה!", - "Scan for documents from {{path}}": "סרוק מסמכים מ-{{path}}", - "Search": "חפש", - "Search a model": "חפש מודל", - "Search Documents": "חפש מסמכים", - "Search Prompts": "חפש פקודות", - "See readme.md for instructions": "ראה את readme.md להוראות", - "See what's new": "ראה מה חדש", - "Seed": "זרע", - "Select a mode": "בחר מצב", - "Select a model": "בחר מודל", - "Select an Ollama instance": "בחר מופע של Ollama", - "Select model": "בחר מודל", - "Send a Message": "שלח הודעה", - "Send message": "שלח הודעה", - "September": "ספטמבר", - "Server connection verified": "החיבור לשרת אומת", - "Set as default": "הגדר כברירת מחדל", - "Set Default Model": "הגדר מודל ברירת מחדל", - "Set embedding model (e.g. {{model}})": "הגדר מודל הטמעה (למשל {{model}})", - "Set Image Size": "הגדר גודל תמונה", - "Set Model": "הגדר מודל", - "Set reranking model (e.g. {{model}})": "הגדר מודל דירוג מחדש (למשל {{model}})", - "Set Steps": "הגדר שלבים", - "Set Title Auto-Generation Model": "הגדר מודל יצירת כותרת אוטומטית", - "Set Voice": "הגדר קול", - "Settings": "הגדרות", - "Settings saved successfully!": "ההגדרות נשמרו בהצלחה!", - "Share": "שתף", - "Share Chat": "שתף צ'אט", - "Share to OpenWebUI Community": "שתף לקהילת OpenWebUI", - "short-summary": "סיכום קצר", - "Show": "הצג", - "Show Additional Params": "הצג פרמטרים נוספים", - "Show shortcuts": "הצג קיצורי דרך", - "Showcased creativity": "הצגת יצירתיות", - "sidebar": "סרגל צד", - "Sign In": "התחבר", - "Sign out": "התנתק", - "Signed In": "מחובר", - "Simulation": "סימולציה", - "Single Sign-On": "כניסה אחת לכל המערכות", - "Site": "אתר", - "Size": "גודל", - "Skipped": "דלג", - "Small size": "גודל קטן", - "Sort by": "מיין לפי", - "Source code": "קוד מקור", - "Source Code View": "הצגת קוד מקור", - "Source not available": "המקור לא זמין", - "Specify a different location": "ציין מיקום אחר", - "Speech Recognition": "זיהוי דיבור", - "Split": "חלק", - "Split screen": "מסך מחולק", - "SSH Tunnel": "מנהרת SSH", - "SSH Tunnel Configuration": "תצורת מנהרת SSH", - "Start": "התחל", - "Start Over": "התחל מחדש", - "Start with a new search": "התחל עם חיפוש חדש", - "Started": "התחיל", - "Status": "מצב", - "Step": "שלב", - "Stop": "עצור", - "Storage": "אחסון", - "Storage Configuration": "תצורת אחסון", - "Storage path": "נתיב אחסון", - "Submit": "שלח", - "Submit Feedback": "שלח משוב", - "Submit request": "שלח בקשה", - "Success": "הצלחה", - "Successfully saved": "נשמר בהצלחה", - "Suggest a correction": "הצע תיקון", - "Suggest changes": "הצע שינויים", - "Suggest improvement": "הצע שיפור", - "Suggested Content": "תוכן מוצע", - "Suggested Model": "מודל מוצע", - "Suggested Prompts": "פקודות מוצעות", - "Summary": "סיכום", - "Support": "תמיכה", - "Support portal": "פורטל תמיכה", - "Supported Files": "קבצים נתמכים", - "Suspend": "השעה", - "Switch": "החלף", - "Switch accounts": "החלף חשבונות", - "Switch Languages": "החלף שפות", - "Switch model": "החלף מודל", - "Switch Theme": "החלף נושא", - "Switch to a different model": "עבור למודל אחר", - "System": "מערכת", - "System Check": "בדיקת מערכת", - "System Settings": "הגדרות מערכת", - "Tab": "לשונית", - "Table of Contents": "תוכן העניינים", - "Tag": "תג", - "Take a look at our new features!": "הצצה בתכונות החדשות שלנו!", - "Take Snapshot": "צלם תמונה", - "Tasks": "משימות", - "Technical Details": "פרטים טכניים", - "Template": "תבנית", - "Terms of Service": "תנאי שירות", - "Test Connection": "בדוק חיבור", - "Text": "טקסט", - "Text Area": "אזור טקסט", - "Text Editor": "עורך טקסט", - "Text Field": "שדה טקסט", - "Text Input": "קלט טקסט", - "Text Settings": "הגדרות טקסט", - "Text-to-Speech": "טקסט לדיבור", - "Text-to-Speech Engine": "מנוע טקסט לדיבור", - "Thanks": "תודה", - "Thanks for your feedback!": "תודה על המשוב שלך!", - "The latest updates": "העדכונים האחרונים", - "The new standard in online communication": "התקן החדש בתקשורת מקוונת", - "Theme": "נושא", - "Theme Settings": "הגדרות נושא", - "There are no new updates available": "אין עדכונים חדשים זמינים", - "This action cannot be undone": "פעולה זו לא ניתנת לביטול", - "This is a critical update": "זהו עדכון קריטי", - "This is a required field": "זהו שדה חובה", - "This month": "החודש", - "This week": "השבוע", - "Time": "זמן", - "Time Limit": "מגבלת זמן", - "Time Zone": "אזור זמן", - "To": "אל", - "To do list": "רשימת משימות", - "Toggle": "החלף מצב", - "Toggle Dark Mode": "החלף מצב כהה", - "Toggle Light Mode": "החלף מצב בהיר", - "Toggle navigation": "החלף ניווט", - "Token": "אסימון", - "Toolbar": "סרגל כלים", - "Toolbox": "ארגז כלים", - "Top": "למעלה", - "Total": "סך הכל", - "Trace": "עקוב", - "Track": "עקוב אחרי", - "Tracking": "מעקב", - "Traditional": "מסורתי", - "Train": "רכבת", - "Training": "הדרכה", - "Transaction": "עסקה", - "Transcript": "תמליל", - "Transfer": "העברה", - "Transform": "הפוך", - "Translate": "תרגם", - "Translation": "תרגום", - "Transparency": "שקיפות", - "Transport": "תחבורה", - "Trending": "טרנדים", - "Trial": "ניסיון", - "Triggers": "מפעילים", - "Troubleshoot": "פתרון בעיות", - "Troubleshooting": "פתרון בעיות", - "True": "נכון", - "Trust": "אמון", - "Try Again": "נסה שוב", - "Type": "סוג", - "Type your message": "הקלד את הודעתך", - "Typing": "הקלדה", - "UI Components": "רכיבי ממשק משתמש", - "Unarchive": "בטל ארכיבה", - "Undo": "בטל", - "Uninstall": "הסר התקנה", - "Unique": "ייחודי", - "Unit": "יחידה", - "Universal": "אוניברסלי", - "Unknown": "לא ידוע", - "Unlimited": "לא מוגבל", - "Unlock": "פתח נעילה", - "Unread": "לא נקרא", - "Unsubscribe": "בטל רישום", - "Update": "עדכן", - "Update Available": "עדכון זמין", - "Update Profile": "עדכן פרופיל", - "Updated": "עודכן", - "Upload": "העלה", - "Upload File": "העלה קובץ", - "Upload Image": "העלה תמונה", - "Uptime": "זמן פעילות", - "URL": "כתובת אתר", - "Usage": "שימוש", - "Use": "השתמש", - "User": "משתמש", - "User Agreement": "הסכם משתמש", - "User Guide": "מדריך משתמש", - "User Interface": "ממשק משתמש", - "User Management": "ניהול משתמשים", - "User Profile": "פרופיל משתמש", - "Username": "שם משתמש", - "Users": "משתמשים", - "Utility": "שימושיות", - "Validate": "אמת", - "Validation": "אימות", - "Value": "ערך", - "Values": "ערכים", - "Variable": "משתנה", - "Variants": "נגזרות", - "Various": "שונים", - "Version": "גרסה", - "View": "הצג", - "View Details": "הצג פרטים", - "View more": "הצג עוד", - "Visibility": "נראות", - "Visible": "נראה", - "Visit": "בקר", - "Visitor": "מבקר", - "Visual": "חזותי", - "Vocabulary": "אוצר מילים", - "Voice": "קול", - "Voice Command": "פקודת קול", - "Volume": "נפח", - "Vote": "הצבע", - "Voucher": "שובר", - "Wait": "חכה", - "Waiting": "ממתין", - "Warning": "אזהרה", - "Watch": "צפה", - "Web": "רשת", - "Web Access": "גישה לרשת", - "Web Application": "יישום רשת", - "Web Service": "שירות רשת", - "Website": "אתר אינטרנט", - "Week": "שבוע", - "Welcome": "ברוך הבא", - "What's New": "מה חדש", - "Widget": "וידג'ט", - "Width": "רוחב", - "Window": "חלון", - "Windows": "חלונות", - "Winner": "מנצח", - "Wireless": "אלחוטי", - "Wisdom": "חוכמה", - "Withdraw": "משוך", - "Work": "עבודה", - "Workaround": "פתרון זמני", - "Workflow": "זרימת עבודה", - "Workspace": "סביבת עבודה", - "World": "עולם", - "Write": "כתוב", - "Writer": "כותב", - "Writing": "כתיבה", - "XML": "XML", - "Year": "שנה", - "Yes": "כן", - "Yesterday": "אתמול", - "You": "אתה", - "YouTube": "יוטיוב", - "Zone": "אזור", - "Zoom": "זום" + "'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' או '-1' ללא תפוגה.", + "(Beta)": "(בטא)", + "(e.g. `sh webui.sh --api`)": "(למשל `sh webui.sh --api`)", + "(latest)": "(האחרון)", + "{{modelName}} is thinking...": "{{modelName}} חושב...", + "{{user}}'s Chats": "צ'אטים של {{user}}", + "{{webUIName}} Backend Required": "נדרש Backend של {{webUIName}}", + "a user": "משתמש", + "About": "אודות", + "Account": "חשבון", + "Accurate information": "מידע מדויק", + "Add a model": "הוסף מודל", + "Add a model tag name": "הוסף שם תג למודל", + "Add a short description about what this modelfile does": "הוסף תיאור קצר על מה שהקובץ מודל עושה", + "Add a short title for this prompt": "הוסף כותרת קצרה לפקודה זו", + "Add a tag": "הוסף תג", + "Add custom prompt": "הוסף פקודה מותאמת אישית", + "Add Docs": "הוסף מסמכים", + "Add Files": "הוסף קבצים", + "Add message": "הוסף הודעה", + "Add Model": "הוסף מודל", + "Add Tags": "הוסף תגים", + "Add User": "הוסף משתמש", + "Adjusting these settings will apply changes universally to all users.": "התאמת הגדרות אלו תחול על כל המשתמשים.", + "admin": "מנהל", + "Admin Panel": "לוח בקרה למנהל", + "Admin Settings": "הגדרות מנהל", + "Advanced Parameters": "פרמטרים מתקדמים", + "all": "הכל", + "All Documents": "כל המסמכים", + "All Users": "כל המשתמשים", + "Allow": "אפשר", + "Allow Chat Deletion": "אפשר מחיקת צ'אט", + "alphanumeric characters and hyphens": "תווים אלפאנומריים ומקפים", + "Already have an account?": "כבר יש לך חשבון?", + "an assistant": "עוזר", + "and": "וגם", + "and create a new shared link.": "וצור קישור משותף חדש.", + "API Base URL": "כתובת URL בסיסית ל-API", + "API Key": "מפתח API", + "API Key created.": "מפתח API נוצר.", + "API keys": "מפתחות API", + "API RPM": "RPM של API", + "April": "אפריל", + "Archive": "ארכיון", + "Archived Chats": "צ'אטים מאורכבים", + "are allowed - Activate this command by typing": "מותרים - הפעל פקודה זו על ידי הקלדה", + "Are you sure?": "האם אתה בטוח?", + "Attach file": "צרף קובץ", + "Attention to detail": "תשומת לב לפרטים", + "Audio": "אודיו", + "August": "אוגוסט", + "Auto-playback response": "תגובת השמעה אוטומטית", + "Auto-send input after 3 sec.": "שליחת קלט אוטומטית אחרי 3 שניות", + "AUTOMATIC1111 Base URL": "כתובת URL בסיסית של AUTOMATIC1111", + "AUTOMATIC1111 Base URL is required.": "נדרשת כתובת URL בסיסית של AUTOMATIC1111", + "available!": "זמין!", + "Back": "חזור", + "Bad Response": "תגובה שגויה", + "before": "לפני", + "Being lazy": "להיות עצלן", + "Builder Mode": "מצב בונה", + "Bypass SSL verification for Websites": "עקוף אימות SSL עבור אתרים", + "Cancel": "בטל", + "Categories": "קטגוריות", + "Change Password": "שנה סיסמה", + "Chat": "צ'אט", + "Chat History": "היסטוריית צ'אט", + "Chat History is off for this browser.": "היסטוריית הצ'אט כבויה לדפדפן זה.", + "Chats": "צ'אטים", + "Check Again": "בדוק שוב", + "Check for updates": "בדוק עדכונים", + "Checking for updates...": "בודק עדכונים...", + "Choose a model before saving...": "בחר מודל לפני השמירה...", + "Chunk Overlap": "חפיפת נתונים", + "Chunk Params": "פרמטרי נתונים", + "Chunk Size": "גודל נתונים", + "Citation": "ציטוט", + "Click here for help.": "לחץ כאן לעזרה.", + "Click here to": "לחץ כאן כדי", + "Click here to check other modelfiles.": "לחץ כאן לבדיקת קבצי מודלים אחרים.", + "Click here to select": "לחץ כאן לבחירה", + "Click here to select a csv file.": "לחץ כאן לבחירת קובץ csv.", + "Click here to select documents.": "לחץ כאן לבחירת מסמכים.", + "click here.": "לחץ כאן.", + "Click on the user role button to change a user's role.": "לחץ על כפתור תפקיד המשתמש כדי לשנות את תפקיד המשתמש.", + "Close": "סגור", + "Collection": "אוסף", + "ComfyUI": "ComfyUI", + "ComfyUI Base URL": "כתובת URL בסיסית של ComfyUI", + "ComfyUI Base URL is required.": "נדרשת כתובת URL בסיסית של ComfyUI", + "Command": "פקודה", + "Confirm Password": "אשר סיסמה", + "Connections": "חיבורים", + "Content": "תוכן", + "Context Length": "אורך הקשר", + "Continue Response": "המשך תגובה", + "Conversation Mode": "מצב שיחה", + "Copied shared chat URL to clipboard!": "העתקת כתובת URL של צ'אט משותף ללוח!", + "Copy": "העתק", + "Copy last code block": "העתק את בלוק הקוד האחרון", + "Copy last response": "העתק את התגובה האחרונה", + "Copy Link": "העתק קישור", + "Copying to clipboard was successful!": "ההעתקה ללוח הייתה מוצלחת!", + "Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "צור ביטוי תמציתי של 3-5 מילים ככותרת לשאילתה הבאה, תוך שמירה מדויקת על מגבלת 3-5 המילים והימנעות משימוש במילה 'כותרת':", + "Create a modelfile": "צור קובץ מודל", + "Create Account": "צור חשבון", + "Create new key": "צור מפתח חדש", + "Create new secret key": "צור מפתח סודי חדש", + "Created at": "נוצר ב", + "Created At": "נוצר ב", + "Current Model": "המודל הנוכחי", + "Current Password": "הסיסמה הנוכחית", + "Custom": "מותאם אישית", + "Customize Ollama models for a specific purpose": "התאמה אישית של מודלים של Ollama למטרה מסוימת", + "Dark": "כהה", + "Dashboard": "לוח בקרה", + "Database": "מסד נתונים", + "DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm", + "December": "דצמבר", + "Default": "ברירת מחדל", + "Default (Automatic1111)": "ברירת מחדל (Automatic1111)", + "Default (SentenceTransformers)": "ברירת מחדל (SentenceTransformers)", + "Default (Web API)": "ברירת מחדל (Web API)", + "Default model updated": "המודל המוגדר כברירת מחדל עודכן", + "Default Prompt Suggestions": "הצעות ברירת מחדל לפקודות", + "Default User Role": "תפקיד משתמש ברירת מחדל", + "delete": "מחק", + "Delete": "מחק", + "Delete a model": "מחק מודל", + "Delete chat": "מחק צ'אט", + "Delete Chat": "מחק צ'אט", + "Delete Chats": "מחק צ'אטים", + "delete this link": "מחק את הקישור הזה", + "Delete User": "מחק משתמש", + "Deleted {{deleteModelTag}}": "נמחק {{deleteModelTag}}", + "Deleted {{tagName}}": "נמחק {{tagName}}", + "Description": "תיאור", + "Didn't fully follow instructions": "לא עקב אחרי ההוראות באופן מלא", + "Disabled": "מושבת", + "Discover a modelfile": "גלה קובץ מודל", + "Discover a prompt": "גלה פקודה", + "Discover, download, and explore custom prompts": "גלה, הורד, וחקור פקודות מותאמות אישית", + "Discover, download, and explore model presets": "גלה, הורד, וחקור הגדרות מודל מוגדרות מראש", + "Display the username instead of You in the Chat": "הצג את שם המשתמש במקום 'אתה' בצ'אט", + "Document": "מסמך", + "Document Settings": "הגדרות מסמך", + "Documents": "מסמכים", + "does not make any external connections, and your data stays securely on your locally hosted server.": "לא מבצע חיבורים חיצוניים, והנתונים שלך נשמרים באופן מאובטח בשרת המקומי שלך.", + "Don't Allow": "אל תאפשר", + "Don't have an account?": "אין לך חשבון?", + "Don't like the style": "לא אוהב את הסגנון", + "Download": "הורד", + "Download canceled": "ההורדה בוטלה", + "Download Database": "הורד מסד נתונים", + "Drop any files here to add to the conversation": "גרור כל קובץ לכאן כדי להוסיף לשיחה", + "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "למשל '30s', '10m'. יחידות זמן חוקיות הן 's', 'm', 'h'.", + "Edit": "ערוך", + "Edit Doc": "ערוך מסמך", + "Edit User": "ערוך משתמש", + "Email": "דוא\"ל", + "Embedding Model": "מודל הטמעה", + "Embedding Model Engine": "מנוע מודל הטמעה", + "Embedding model set to \"{{embedding_model}}\"": "מודל ההטמעה הוגדר ל-\"{{embedding_model}}\"", + "Enable Chat History": "הפעל היסטוריית צ'אט", + "Enable New Sign Ups": "אפשר הרשמות חדשות", + "Enabled": "מופעל", + "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "ודא שקובץ ה-CSV שלך כולל 4 עמודות בסדר הבא: שם, דוא\"ל, סיסמה, תפקיד.", + "Enter {{role}} message here": "הזן הודעת {{role}} כאן", + "Enter Chunk Overlap": "הזן חפיפת נתונים", + "Enter Chunk Size": "הזן גודל נתונים", + "Enter Image Size (e.g. 512x512)": "הזן גודל תמונה (למשל 512x512)", + "Enter language codes": "הזן קודי שפה", + "Enter LiteLLM API Base URL (litellm_params.api_base)": "הזן כתובת URL בסיסית ל-API של LiteLLM (litellm_params.api_base)", + "Enter LiteLLM API Key (litellm_params.api_key)": "הזן מפתח API של LiteLLM (litellm_params.api_key)", + "Enter LiteLLM API RPM (litellm_params.rpm)": "הזן RPM של API של LiteLLM (litellm_params.rpm)", + "Enter LiteLLM Model (litellm_params.model)": "הזן מודל LiteLLM (litellm_params.model)", + "Enter Max Tokens (litellm_params.max_tokens)": "הזן מספר מקסימלי של טוקנים (litellm_params.max_tokens)", + "Enter model tag (e.g. {{modelTag}})": "הזן תג מודל (למשל {{modelTag}})", + "Enter Number of Steps (e.g. 50)": "הזן מספר שלבים (למשל 50)", + "Enter Score": "הזן ציון", + "Enter stop sequence": "הזן רצף עצירה", + "Enter Top K": "הזן Top K", + "Enter URL (e.g. http://127.0.0.1:7860/)": "הזן כתובת URL (למשל http://127.0.0.1:7860/)", + "Enter URL (e.g. http://localhost:11434)": "הזן כתובת URL (למשל http://localhost:11434)", + "Enter Your Email": "הזן את דוא\"ל שלך", + "Enter Your Full Name": "הזן את שמך המלא", + "Enter Your Password": "הזן את הסיסמה שלך", + "Enter Your Role": "הזן את התפקיד שלך", + "Experimental": "ניסיוני", + "Export All Chats (All Users)": "ייצוא כל הצ'אטים (כל המשתמשים)", + "Export Chats": "ייצוא צ'אטים", + "Export Documents Mapping": "ייצוא מיפוי מסמכים", + "Export Modelfiles": "ייצוא קבצי מודלים", + "Export Prompts": "ייצוא פקודות", + "Failed to create API Key.": "יצירת מפתח API נכשלה.", + "Failed to read clipboard contents": "קריאת תוכן הלוח נכשלה", + "February": "פברואר", + "Feel free to add specific details": "נא להוסיף פרטים ספציפיים לפי רצון", + "File Mode": "מצב קובץ", + "File not found.": "הקובץ לא נמצא.", + "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "התגלתה הזיית טביעת אצבע: לא ניתן להשתמש בראשי תיבות כאווטאר. משתמש בתמונת פרופיל ברירת מחדל.", + "Fluidly stream large external response chunks": "שידור נתונים חיצוניים בקצב רציף", + "Focus chat input": "מיקוד הקלט לצ'אט", + "Followed instructions perfectly": "עקב אחר ההוראות במושלמות", + "Format your variables using square brackets like this:": "עצב את המשתנים שלך באמצעות סוגריים מרובעים כך:", + "From (Base Model)": "מ (מודל בסיס)", + "Full Screen Mode": "מצב מסך מלא", + "General": "כללי", + "General Settings": "הגדרות כלליות", + "Generation Info": "מידע על היצירה", + "Good Response": "תגובה טובה", + "has no conversations.": "אין שיחות.", + "Hello, {{name}}": "שלום, {{name}}", + "Help": "עזרה", + "Hide": "הסתר", + "Hide Additional Params": "הסתר פרמטרים נוספים", + "How can I help you today?": "כיצד אוכל לעזור לך היום?", + "Hybrid Search": "חיפוש היברידי", + "Image Generation (Experimental)": "יצירת תמונות (ניסיוני)", + "Image Generation Engine": "מנוע יצירת תמונות", + "Image Settings": "הגדרות תמונה", + "Images": "תמונות", + "Import Chats": "יבוא צ'אטים", + "Import Documents Mapping": "יבוא מיפוי מסמכים", + "Import Modelfiles": "יבוא קבצי מודלים", + "Import Prompts": "יבוא פקודות", + "Include `--api` flag when running stable-diffusion-webui": "כלול את הדגל `--api` בעת הרצת stable-diffusion-webui", + "Input commands": "פקודות קלט", + "Interface": "ממשק", + "Invalid Tag": "תג לא חוקי", + "January": "ינואר", + "join our Discord for help.": "הצטרף ל-Discord שלנו לעזרה.", + "JSON": "JSON", + "July": "יולי", + "June": "יוני", + "JWT Expiration": "תפוגת JWT", + "JWT Token": "אסימון JWT", + "Keep Alive": "השאר פעיל", + "Keyboard shortcuts": "קיצורי מקלדת", + "Language": "שפה", + "Last Active": "פעיל לאחרונה", + "Light": "בהיר", + "Listening...": "מאזין...", + "LLMs can make mistakes. Verify important information.": "מודלים בשפה טבעית יכולים לטעות. אמת מידע חשוב.", + "Made by OpenWebUI Community": "נוצר על ידי קהילת OpenWebUI", + "Make sure to enclose them with": "ודא להקיף אותם עם", + "Manage LiteLLM Models": "נהל מודלים של LiteLLM", + "Manage Models": "נהל מודלים", + "Manage Ollama Models": "נהל מודלים של Ollama", + "March": "מרץ", + "Max Tokens": "מקסימום טוקנים", + "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "ניתן להוריד מקסימום 3 מודלים בו זמנית. אנא נסה שוב מאוחר יותר.", + "May": "מאי", + "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "הודעות שתשלח לאחר יצירת הקישור שלך לא ישותפו. משתמשים עם הכתובת URL יוכלו לצפות בצ'אט המשותף.", + "Minimum Score": "ציון מינימלי", + "Mirostat": "Mirostat", + "Mirostat Eta": "Mirostat Eta", + "Mirostat Tau": "Mirostat Tau", + "MMMM DD, YYYY": "DD בMMMM, YYYY", + "MMMM DD, YYYY HH:mm": "DD בMMMM, YYYY HH:mm", + "Model '{{modelName}}' has been successfully downloaded.": "המודל '{{modelName}}' הורד בהצלחה.", + "Model '{{modelTag}}' is already in queue for downloading.": "המודל '{{modelTag}}' כבר בתור להורדה.", + "Model {{modelId}} not found": "המודל {{modelId}} לא נמצא", + "Model {{modelName}} already exists.": "המודל {{modelName}} כבר קיים.", + "Model filesystem path detected. Model shortname is required for update, cannot continue.": "נתיב מערכת הקבצים של המודל זוהה. נדרש שם קצר של המודל לעדכון, לא ניתן להמשיך.", + "Model Name": "שם המודל", + "Model not selected": "לא נבחר מודל", + "Model Tag Name": "שם תג המודל", + "Model Whitelisting": "רישום לבן של מודלים", + "Model(s) Whitelisted": "מודלים שנכללו ברשימה הלבנה", + "Modelfile": "קובץ מודל", + "Modelfile Advanced Settings": "הגדרות מתקדמות לקובץ מודל", + "Modelfile Content": "תוכן קובץ מודל", + "Modelfiles": "קבצי מודל", + "Models": "מודלים", + "More": "עוד", + "My Documents": "המסמכים שלי", + "My Modelfiles": "קבצי המודל שלי", + "My Prompts": "הפקודות שלי", + "Name": "שם", + "Name Tag": "תג שם", + "Name your modelfile": "תן שם לקובץ המודל שלך", + "New Chat": "צ'אט חדש", + "New Password": "סיסמה חדשה", + "No results found": "לא נמצאו תוצאות", + "No source available": "אין מקור זמין", + "Not factually correct": "לא נכון מבחינה עובדתית", + "Not sure what to add?": "לא בטוח מה להוסיף?", + "Not sure what to write? Switch to": "לא בטוח מה לכתוב? החלף ל", + "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "הערה: אם תקבע ציון מינימלי, החיפוש יחזיר רק מסמכים עם ציון שגבוה או שווה לציון המינימלי.", + "Notifications": "התראות", + "November": "נובמבר", + "October": "אוקטובר", + "Off": "כבוי", + "Okay, Let's Go!": "בסדר, בואו נתחיל!", + "OLED Dark": "OLED כהה", + "Ollama": "Ollama", + "Ollama Base URL": "כתובת URL בסיסית של Ollama", + "Ollama Version": "גרסת Ollama", + "On": "פועל", + "Only": "רק", + "Only alphanumeric characters and hyphens are allowed in the command string.": "רק תווים אלפאנומריים ומקפים מותרים במחרוזת הפקודה.", + "Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "אופס! תחזיק מעמד! הקבצים שלך עדיין בתהליך העיבוד. אנו מבשלים אותם לשלמות. נא להתאזר בסבלנות ונודיע לך ברגע שיהיו מוכנים.", + "Oops! Looks like the URL is invalid. Please double-check and try again.": "אופס! נראה שהכתובת URL אינה תקינה. אנא בדוק שוב ונסה שנית.", + "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "אופס! אתה משתמש בשיטה לא נתמכת (רק חזית). אנא שרת את ממשק המשתמש האינטרנטי מהשרת האחורי.", + "Open": "פתח", + "Open AI": "Open AI", + "Open AI (Dall-E)": "Open AI (Dall-E)", + "Open new chat": "פתח צ'אט חדש", + "OpenAI": "OpenAI", + "OpenAI API": "API של OpenAI", + "OpenAI API Config": "תצורת API של OpenAI", + "OpenAI API Key is required.": "נדרש מפתח API של OpenAI.", + "OpenAI URL/Key required.": "נדרשת כתובת URL/מפתח של OpenAI.", + "or": "או", + "Other": "אחר", + "Overview": "סקירה כללית", + "Parameters": "פרמטרים", + "Password": "סיסמה", + "PDF document (.pdf)": "מסמך PDF (.pdf)", + "PDF Extract Images (OCR)": "חילוץ תמונות מ-PDF (OCR)", + "pending": "ממתין", + "Permission denied when accessing microphone: {{error}}": "ההרשאה נדחתה בעת גישה למיקרופון: {{error}}", + "Plain text (.txt)": "טקסט פשוט (.txt)", + "Playground": "אזור משחקים", + "Positive attitude": "גישה חיובית", + "Previous 30 days": "30 הימים הקודמים", + "Previous 7 days": "7 הימים הקודמים", + "Profile Image": "תמונת פרופיל", + "Prompt": "פקודה", + "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "פקודה (למשל, ספר לי עובדה מעניינת על האימפריה הרומית)", + "Prompt Content": "תוכן הפקודה", + "Prompt suggestions": "הצעות לפקודות", + "Prompts": "פקודות", + "Pull \"{{searchValue}}\" from Ollama.com": "משוך \"{{searchValue}}\" מ-Ollama.com", + "Pull a model from Ollama.com": "משוך מודל מ-Ollama.com", + "Pull Progress": "משוך התקדמות", + "Query Params": "פרמטרי שאילתה", + "RAG Template": "תבנית RAG", + "Raw Format": "פורמט גולמי", + "Read Aloud": "קרא בקול", + "Record voice": "הקלט קול", + "Redirecting you to OpenWebUI Community": "מפנה אותך לקהילת OpenWebUI", + "Refused when it shouldn't have": "נדחה כאשר לא היה צריך", + "Regenerate": "הפק מחדש", + "Release Notes": "הערות שחרור", + "Remove": "הסר", + "Remove Model": "הסר מודל", + "Rename": "שנה שם", + "Repeat Last N": "חזור על ה-N האחרונים", + "Repeat Penalty": "עונש חזרה", + "Request Mode": "מצב בקשה", + "Reranking Model": "מודל דירוג מחדש", + "Reranking model disabled": "מודל דירוג מחדש מושבת", + "Reranking model set to \"{{reranking_model}}\"": "מודל דירוג מחדש הוגדר ל-\"{{reranking_model}}\"", + "Reset Vector Storage": "איפוס אחסון וקטורים", + "Response AutoCopy to Clipboard": "העתקה אוטומטית של תגובה ללוח", + "Role": "תפקיד", + "Rosé Pine": "Rosé Pine", + "Rosé Pine Dawn": "Rosé Pine Dawn", + "Save": "שמור", + "Save & Create": "שמור וצור", + "Save & Submit": "שמור ושלח", + "Save & Update": "שמור ועדכן", + "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "שמירת יומני צ'אט ישירות באחסון הדפדפן שלך אינה נתמכת יותר. אנא הקדש רגע להוריד ולמחוק את יומני הצ'אט שלך על ידי לחיצה על הכפתור למטה. אל דאגה, באפשרותך לייבא מחדש בקלות את יומני הצ'אט שלך לשרת האחורי דרך", + "Scan": "סרוק", + "Scan complete!": "הסריקה הושלמה!", + "Scan for documents from {{path}}": "סרוק מסמכים מ-{{path}}", + "Search": "חפש", + "Search a model": "חפש מודל", + "Search Documents": "חפש מסמכים", + "Search Prompts": "חפש פקודות", + "See readme.md for instructions": "ראה את readme.md להוראות", + "See what's new": "ראה מה חדש", + "Seed": "זרע", + "Select a mode": "בחר מצב", + "Select a model": "בחר מודל", + "Select an Ollama instance": "בחר מופע של Ollama", + "Select model": "בחר מודל", + "Send a Message": "שלח הודעה", + "Send message": "שלח הודעה", + "September": "ספטמבר", + "Server connection verified": "החיבור לשרת אומת", + "Set as default": "הגדר כברירת מחדל", + "Set Default Model": "הגדר מודל ברירת מחדל", + "Set embedding model (e.g. {{model}})": "הגדר מודל הטמעה (למשל {{model}})", + "Set Image Size": "הגדר גודל תמונה", + "Set Model": "הגדר מודל", + "Set reranking model (e.g. {{model}})": "הגדר מודל דירוג מחדש (למשל {{model}})", + "Set Steps": "הגדר שלבים", + "Set Title Auto-Generation Model": "הגדר מודל יצירת כותרת אוטומטית", + "Set Voice": "הגדר קול", + "Settings": "הגדרות", + "Settings saved successfully!": "ההגדרות נשמרו בהצלחה!", + "Share": "שתף", + "Share Chat": "שתף צ'אט", + "Share to OpenWebUI Community": "שתף לקהילת OpenWebUI", + "short-summary": "סיכום קצר", + "Show": "הצג", + "Show Additional Params": "הצג פרמטרים נוספים", + "Show shortcuts": "הצג קיצורי דרך", + "Showcased creativity": "הצגת יצירתיות", + "sidebar": "סרגל צד", + "Sign in": "", + "Sign Out": "", + "Sign up": "", + "Signing in": "", + "Source": "", + "Speech recognition error: {{error}}": "", + "Speech-to-Text Engine": "", + "SpeechRecognition API is not supported in this browser.": "", + "Stop Sequence": "", + "STT Settings": "", + "Submit": "שלח", + "Subtitle (e.g. about the Roman Empire)": "", + "Success": "הצלחה", + "Successfully updated.": "", + "Suggested": "", + "Sync All": "", + "System": "מערכת", + "System Prompt": "", + "Tags": "", + "Tell us more:": "", + "Temperature": "", + "Template": "תבנית", + "Text Completion": "", + "Text-to-Speech Engine": "מנוע טקסט לדיבור", + "Tfs Z": "", + "Thanks for your feedback!": "תודה על המשוב שלך!", + "The score should be a value between 0.0 (0%) and 1.0 (100%).": "", + "Theme": "נושא", + "This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "", + "This setting does not sync across browsers or devices.": "", + "Thorough explanation": "", + "Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "", + "Title": "", + "Title (e.g. Tell me a fun fact)": "", + "Title Auto-Generation": "", + "Title cannot be an empty string.": "", + "Title Generation Prompt": "", + "to": "", + "To access the available model names for downloading,": "", + "To access the GGUF models available for downloading,": "", + "to chat input.": "", + "Today": "", + "Toggle settings": "", + "Toggle sidebar": "", + "Top K": "", + "Top P": "", + "Trouble accessing Ollama?": "", + "TTS Settings": "", + "Type Hugging Face Resolve (Download) URL": "", + "Uh-oh! There was an issue connecting to {{provider}}.": "", + "Unknown File Type '{{file_type}}', but accepting and treating as plain text": "", + "Update and Copy Link": "", + "Update password": "", + "Upload a GGUF model": "", + "Upload files": "", + "Upload Progress": "", + "URL Mode": "", + "Use '#' in the prompt input to load and select your documents.": "", + "Use Gravatar": "", + "Use Initials": "", + "user": "", + "User Permissions": "", + "Users": "משתמשים", + "Utilize": "", + "Valid time units:": "", + "variable": "", + "variable to have them replaced with clipboard content.": "", + "Version": "גרסה", + "Warning: If you update or change your embedding model, you will need to re-import all documents.": "", + "Web": "רשת", + "Web Loader Settings": "", + "Web Params": "", + "Webhook URL": "", + "WebUI Add-ons": "", + "WebUI Settings": "", + "WebUI will make requests to": "", + "What’s New in": "", + "When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "", + "Whisper (Local)": "", + "Write a prompt suggestion (e.g. Who are you?)": "", + "Write a summary in 50 words that summarizes [topic or keyword].": "", + "Yesterday": "אתמול", + "You": "אתה", + "You have no archived conversations.": "", + "You have shared this chat": "", + "You're a helpful assistant.": "", + "You're now logged in.": "", + "Youtube": "", + "Youtube Loader Settings": "" } From 7e0d3496b564b5dc14bfe158b260955e5625023d Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Mon, 13 May 2024 11:27:58 -1000 Subject: [PATCH 25/29] fix: 1st #2208 --- src/lib/components/chat/Messages.svelte | 50 ++++++++++--------- .../chat/Messages/RateComment.svelte | 4 +- .../chat/Messages/ResponseMessage.svelte | 4 +- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte index 3ef99594e..68cb985b6 100644 --- a/src/lib/components/chat/Messages.svelte +++ b/src/lib/components/chat/Messages.svelte @@ -309,31 +309,33 @@ copyToClipboard={copyToClipboardWithToast} /> {:else} - { - console.log('save', e); + {#key message.id} + { + console.log('save', e); - const message = e.detail; - history.messages[message.id] = message; - await updateChatById(localStorage.token, chatId, { - messages: messages, - history: history - }); - }} - /> + const message = e.detail; + history.messages[message.id] = message; + await updateChatById(localStorage.token, chatId, { + messages: messages, + history: history + }); + }} + /> + {/key} {/if} diff --git a/src/lib/components/chat/Messages/RateComment.svelte b/src/lib/components/chat/Messages/RateComment.svelte index 2c6d3608e..895143e02 100644 --- a/src/lib/components/chat/Messages/RateComment.svelte +++ b/src/lib/components/chat/Messages/RateComment.svelte @@ -39,9 +39,9 @@ let selectedReason = null; let comment = ''; - $: if (message.annotation.rating === 1) { + $: if (message?.annotation?.rating === 1) { reasons = LIKE_REASONS; - } else if (message.annotation.rating === -1) { + } else if (message?.annotation?.rating === -1) { reasons = DISLIKE_REASONS; } diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index 5b228a9ff..0b7c5e876 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -65,8 +65,8 @@ let generatingImage = false; let showRateComment = false; - let showCitationModal = false; + let selectedCitation = null; $: tokens = marked.lexer(sanitizeResponseContent(message.content)); @@ -902,7 +902,7 @@ {/if} - {#if showRateComment} + {#if message.done && showRateComment} Date: Mon, 13 May 2024 11:32:21 -1000 Subject: [PATCH 26/29] refac: rename --- backend/config.py | 90 ++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/backend/config.py b/backend/config.py index 106044540..112edba90 100644 --- a/backend/config.py +++ b/backend/config.py @@ -201,7 +201,7 @@ def get_config_value(config_path: str): T = TypeVar("T") -class PersistedConfig(Generic[T]): +class PersistentConfig(Generic[T]): def __init__(self, env_name: str, config_path: str, env_value: T): self.env_name = env_name self.config_path = config_path @@ -219,13 +219,13 @@ class PersistedConfig(Generic[T]): @property def __dict__(self): raise TypeError( - "PersistedConfig object cannot be converted to dict, use config_get or .value instead." + "PersistentConfig object cannot be converted to dict, use config_get or .value instead." ) def __getattribute__(self, item): if item == "__dict__": raise TypeError( - "PersistedConfig object cannot be converted to dict, use config_get or .value instead." + "PersistentConfig object cannot be converted to dict, use config_get or .value instead." ) return super().__getattribute__(item) @@ -247,13 +247,13 @@ class PersistedConfig(Generic[T]): class AppConfig: - _state: dict[str, PersistedConfig] + _state: dict[str, PersistentConfig] def __init__(self): super().__setattr__("_state", {}) def __setattr__(self, key, value): - if isinstance(value, PersistedConfig): + if isinstance(value, PersistentConfig): self._state[key] = value else: self._state[key].value = value @@ -271,7 +271,7 @@ WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true" WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get( "WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None ) -JWT_EXPIRES_IN = PersistedConfig( +JWT_EXPIRES_IN = PersistentConfig( "JWT_EXPIRES_IN", "auth.jwt_expiry", os.environ.get("JWT_EXPIRES_IN", "-1") ) @@ -409,7 +409,7 @@ OLLAMA_BASE_URLS = os.environ.get("OLLAMA_BASE_URLS", "") OLLAMA_BASE_URLS = OLLAMA_BASE_URLS if OLLAMA_BASE_URLS != "" else OLLAMA_BASE_URL OLLAMA_BASE_URLS = [url.strip() for url in OLLAMA_BASE_URLS.split(";")] -OLLAMA_BASE_URLS = PersistedConfig( +OLLAMA_BASE_URLS = PersistentConfig( "OLLAMA_BASE_URLS", "ollama.base_urls", OLLAMA_BASE_URLS ) @@ -428,7 +428,9 @@ OPENAI_API_KEYS = os.environ.get("OPENAI_API_KEYS", "") OPENAI_API_KEYS = OPENAI_API_KEYS if OPENAI_API_KEYS != "" else OPENAI_API_KEY OPENAI_API_KEYS = [url.strip() for url in OPENAI_API_KEYS.split(";")] -OPENAI_API_KEYS = PersistedConfig("OPENAI_API_KEYS", "openai.api_keys", OPENAI_API_KEYS) +OPENAI_API_KEYS = PersistentConfig( + "OPENAI_API_KEYS", "openai.api_keys", OPENAI_API_KEYS +) OPENAI_API_BASE_URLS = os.environ.get("OPENAI_API_BASE_URLS", "") OPENAI_API_BASE_URLS = ( @@ -439,7 +441,7 @@ OPENAI_API_BASE_URLS = [ url.strip() if url != "" else "https://api.openai.com/v1" for url in OPENAI_API_BASE_URLS.split(";") ] -OPENAI_API_BASE_URLS = PersistedConfig( +OPENAI_API_BASE_URLS = PersistentConfig( "OPENAI_API_BASE_URLS", "openai.api_base_urls", OPENAI_API_BASE_URLS ) @@ -458,7 +460,7 @@ OPENAI_API_BASE_URL = "https://api.openai.com/v1" # WEBUI #################################### -ENABLE_SIGNUP = PersistedConfig( +ENABLE_SIGNUP = PersistentConfig( "ENABLE_SIGNUP", "ui.enable_signup", ( @@ -467,11 +469,11 @@ ENABLE_SIGNUP = PersistedConfig( else os.environ.get("ENABLE_SIGNUP", "True").lower() == "true" ), ) -DEFAULT_MODELS = PersistedConfig( +DEFAULT_MODELS = PersistentConfig( "DEFAULT_MODELS", "ui.default_models", os.environ.get("DEFAULT_MODELS", None) ) -DEFAULT_PROMPT_SUGGESTIONS = PersistedConfig( +DEFAULT_PROMPT_SUGGESTIONS = PersistentConfig( "DEFAULT_PROMPT_SUGGESTIONS", "ui.prompt_suggestions", [ @@ -505,7 +507,7 @@ DEFAULT_PROMPT_SUGGESTIONS = PersistedConfig( ], ) -DEFAULT_USER_ROLE = PersistedConfig( +DEFAULT_USER_ROLE = PersistentConfig( "DEFAULT_USER_ROLE", "ui.default_user_role", os.getenv("DEFAULT_USER_ROLE", "pending"), @@ -515,25 +517,25 @@ USER_PERMISSIONS_CHAT_DELETION = ( os.environ.get("USER_PERMISSIONS_CHAT_DELETION", "True").lower() == "true" ) -USER_PERMISSIONS = PersistedConfig( +USER_PERMISSIONS = PersistentConfig( "USER_PERMISSIONS", "ui.user_permissions", {"chat": {"deletion": USER_PERMISSIONS_CHAT_DELETION}}, ) -ENABLE_MODEL_FILTER = PersistedConfig( +ENABLE_MODEL_FILTER = PersistentConfig( "ENABLE_MODEL_FILTER", "model_filter.enable", os.environ.get("ENABLE_MODEL_FILTER", "False").lower() == "true", ) MODEL_FILTER_LIST = os.environ.get("MODEL_FILTER_LIST", "") -MODEL_FILTER_LIST = PersistedConfig( +MODEL_FILTER_LIST = PersistentConfig( "MODEL_FILTER_LIST", "model_filter.list", [model.strip() for model in MODEL_FILTER_LIST.split(";")], ) -WEBHOOK_URL = PersistedConfig( +WEBHOOK_URL = PersistentConfig( "WEBHOOK_URL", "webhook_url", os.environ.get("WEBHOOK_URL", "") ) @@ -573,40 +575,40 @@ else: CHROMA_HTTP_SSL = os.environ.get("CHROMA_HTTP_SSL", "false").lower() == "true" # this uses the model defined in the Dockerfile ENV variable. If you dont use docker or docker based deployments such as k8s, the default embedding model will be used (sentence-transformers/all-MiniLM-L6-v2) -RAG_TOP_K = PersistedConfig( +RAG_TOP_K = PersistentConfig( "RAG_TOP_K", "rag.top_k", int(os.environ.get("RAG_TOP_K", "5")) ) -RAG_RELEVANCE_THRESHOLD = PersistedConfig( +RAG_RELEVANCE_THRESHOLD = PersistentConfig( "RAG_RELEVANCE_THRESHOLD", "rag.relevance_threshold", float(os.environ.get("RAG_RELEVANCE_THRESHOLD", "0.0")), ) -ENABLE_RAG_HYBRID_SEARCH = PersistedConfig( +ENABLE_RAG_HYBRID_SEARCH = PersistentConfig( "ENABLE_RAG_HYBRID_SEARCH", "rag.enable_hybrid_search", os.environ.get("ENABLE_RAG_HYBRID_SEARCH", "").lower() == "true", ) -ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = PersistedConfig( +ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION = PersistentConfig( "ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION", "rag.enable_web_loader_ssl_verification", os.environ.get("ENABLE_RAG_WEB_LOADER_SSL_VERIFICATION", "True").lower() == "true", ) -RAG_EMBEDDING_ENGINE = PersistedConfig( +RAG_EMBEDDING_ENGINE = PersistentConfig( "RAG_EMBEDDING_ENGINE", "rag.embedding_engine", os.environ.get("RAG_EMBEDDING_ENGINE", ""), ) -PDF_EXTRACT_IMAGES = PersistedConfig( +PDF_EXTRACT_IMAGES = PersistentConfig( "PDF_EXTRACT_IMAGES", "rag.pdf_extract_images", os.environ.get("PDF_EXTRACT_IMAGES", "False").lower() == "true", ) -RAG_EMBEDDING_MODEL = PersistedConfig( +RAG_EMBEDDING_MODEL = PersistentConfig( "RAG_EMBEDDING_MODEL", "rag.embedding_model", os.environ.get("RAG_EMBEDDING_MODEL", "sentence-transformers/all-MiniLM-L6-v2"), @@ -621,7 +623,7 @@ RAG_EMBEDDING_MODEL_TRUST_REMOTE_CODE = ( os.environ.get("RAG_EMBEDDING_MODEL_TRUST_REMOTE_CODE", "").lower() == "true" ) -RAG_RERANKING_MODEL = PersistedConfig( +RAG_RERANKING_MODEL = PersistentConfig( "RAG_RERANKING_MODEL", "rag.reranking_model", os.environ.get("RAG_RERANKING_MODEL", ""), @@ -665,10 +667,10 @@ if USE_CUDA.lower() == "true": else: DEVICE_TYPE = "cpu" -CHUNK_SIZE = PersistedConfig( +CHUNK_SIZE = PersistentConfig( "CHUNK_SIZE", "rag.chunk_size", int(os.environ.get("CHUNK_SIZE", "1500")) ) -CHUNK_OVERLAP = PersistedConfig( +CHUNK_OVERLAP = PersistentConfig( "CHUNK_OVERLAP", "rag.chunk_overlap", int(os.environ.get("CHUNK_OVERLAP", "100")), @@ -688,18 +690,18 @@ And answer according to the language of the user's question. Given the context information, answer the query. Query: [query]""" -RAG_TEMPLATE = PersistedConfig( +RAG_TEMPLATE = PersistentConfig( "RAG_TEMPLATE", "rag.template", os.environ.get("RAG_TEMPLATE", DEFAULT_RAG_TEMPLATE), ) -RAG_OPENAI_API_BASE_URL = PersistedConfig( +RAG_OPENAI_API_BASE_URL = PersistentConfig( "RAG_OPENAI_API_BASE_URL", "rag.openai_api_base_url", os.getenv("RAG_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL), ) -RAG_OPENAI_API_KEY = PersistedConfig( +RAG_OPENAI_API_KEY = PersistentConfig( "RAG_OPENAI_API_KEY", "rag.openai_api_key", os.getenv("RAG_OPENAI_API_KEY", OPENAI_API_KEY), @@ -709,7 +711,7 @@ ENABLE_RAG_LOCAL_WEB_FETCH = ( os.getenv("ENABLE_RAG_LOCAL_WEB_FETCH", "False").lower() == "true" ) -YOUTUBE_LOADER_LANGUAGE = PersistedConfig( +YOUTUBE_LOADER_LANGUAGE = PersistentConfig( "YOUTUBE_LOADER_LANGUAGE", "rag.youtube_loader_language", os.getenv("YOUTUBE_LOADER_LANGUAGE", "en").split(","), @@ -730,49 +732,49 @@ WHISPER_MODEL_AUTO_UPDATE = ( # Images #################################### -IMAGE_GENERATION_ENGINE = PersistedConfig( +IMAGE_GENERATION_ENGINE = PersistentConfig( "IMAGE_GENERATION_ENGINE", "image_generation.engine", os.getenv("IMAGE_GENERATION_ENGINE", ""), ) -ENABLE_IMAGE_GENERATION = PersistedConfig( +ENABLE_IMAGE_GENERATION = PersistentConfig( "ENABLE_IMAGE_GENERATION", "image_generation.enable", os.environ.get("ENABLE_IMAGE_GENERATION", "").lower() == "true", ) -AUTOMATIC1111_BASE_URL = PersistedConfig( +AUTOMATIC1111_BASE_URL = PersistentConfig( "AUTOMATIC1111_BASE_URL", "image_generation.automatic1111.base_url", os.getenv("AUTOMATIC1111_BASE_URL", ""), ) -COMFYUI_BASE_URL = PersistedConfig( +COMFYUI_BASE_URL = PersistentConfig( "COMFYUI_BASE_URL", "image_generation.comfyui.base_url", os.getenv("COMFYUI_BASE_URL", ""), ) -IMAGES_OPENAI_API_BASE_URL = PersistedConfig( +IMAGES_OPENAI_API_BASE_URL = PersistentConfig( "IMAGES_OPENAI_API_BASE_URL", "image_generation.openai.api_base_url", os.getenv("IMAGES_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL), ) -IMAGES_OPENAI_API_KEY = PersistedConfig( +IMAGES_OPENAI_API_KEY = PersistentConfig( "IMAGES_OPENAI_API_KEY", "image_generation.openai.api_key", os.getenv("IMAGES_OPENAI_API_KEY", OPENAI_API_KEY), ) -IMAGE_SIZE = PersistedConfig( +IMAGE_SIZE = PersistentConfig( "IMAGE_SIZE", "image_generation.size", os.getenv("IMAGE_SIZE", "512x512") ) -IMAGE_STEPS = PersistedConfig( +IMAGE_STEPS = PersistentConfig( "IMAGE_STEPS", "image_generation.steps", int(os.getenv("IMAGE_STEPS", 50)) ) -IMAGE_GENERATION_MODEL = PersistedConfig( +IMAGE_GENERATION_MODEL = PersistentConfig( "IMAGE_GENERATION_MODEL", "image_generation.model", os.getenv("IMAGE_GENERATION_MODEL", ""), @@ -782,22 +784,22 @@ IMAGE_GENERATION_MODEL = PersistedConfig( # Audio #################################### -AUDIO_OPENAI_API_BASE_URL = PersistedConfig( +AUDIO_OPENAI_API_BASE_URL = PersistentConfig( "AUDIO_OPENAI_API_BASE_URL", "audio.openai.api_base_url", os.getenv("AUDIO_OPENAI_API_BASE_URL", OPENAI_API_BASE_URL), ) -AUDIO_OPENAI_API_KEY = PersistedConfig( +AUDIO_OPENAI_API_KEY = PersistentConfig( "AUDIO_OPENAI_API_KEY", "audio.openai.api_key", os.getenv("AUDIO_OPENAI_API_KEY", OPENAI_API_KEY), ) -AUDIO_OPENAI_API_MODEL = PersistedConfig( +AUDIO_OPENAI_API_MODEL = PersistentConfig( "AUDIO_OPENAI_API_MODEL", "audio.openai.api_model", os.getenv("AUDIO_OPENAI_API_MODEL", "tts-1"), ) -AUDIO_OPENAI_API_VOICE = PersistedConfig( +AUDIO_OPENAI_API_VOICE = PersistentConfig( "AUDIO_OPENAI_API_VOICE", "audio.openai.api_voice", os.getenv("AUDIO_OPENAI_API_VOICE", "alloy"), From f42819c6ad27324342a1aa4cd2df86ec52f8fb76 Mon Sep 17 00:00:00 2001 From: HAMAD ABDULLA Date: Tue, 14 May 2024 01:49:04 +0300 Subject: [PATCH 27/29] Update Arabic language --- src/lib/i18n/locales/ar-BH/translation.json | 182 ++++++++++---------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index d57282afe..28508f8b5 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -1,11 +1,11 @@ { "'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "", "(Beta)": "(تجريبي)", - "(e.g. `sh webui.sh --api`)": "(مثال `sh webui.sh --api`)", + "(e.g. `sh webui.sh --api`)": "( `sh webui.sh --api`مثال)", "(latest)": "(الأخير)", "{{modelName}} is thinking...": "{{modelName}} ...يفكر", "{{user}}'s Chats": "{{user}}' الدردشات", - "{{webUIName}} Backend Required": "", + "{{webUIName}} Backend Required": "{{webUIName}} مطلوب", "a user": "المستخدم", "About": "عن", "Account": "الحساب", @@ -15,20 +15,20 @@ "Add a short description about what this modelfile does": "أضف وصفًا قصيرًا حول ما يفعله ملف الموديل هذا", "Add a short title for this prompt": "أضف عنوانًا قصيرًا لبداء المحادثة", "Add a tag": "أضافة تاق", - "Add custom prompt": "", + "Add custom prompt": "أضافة مطالبة مخصصه", "Add Docs": "إضافة المستندات", "Add Files": "إضافة ملفات", "Add message": "اضافة رسالة", "Add Model": "اضافة موديل", "Add Tags": "اضافة تاق", "Add User": "اضافة مستخدم", - "Adjusting these settings will apply changes universally to all users.": "سيؤدي ضبط هذه الإعدادات إلى تطبيق التغييرات بشكل عام على كافة المستخدمين.", + "Adjusting these settings will apply changes universally to all users.": "سيؤدي ضبط هذه الإعدادات إلى تطبيق التغييرات بشكل عام على كافة المستخدمين", "admin": "المشرف", "Admin Panel": "لوحة التحكم", "Admin Settings": "اعدادات المشرف", "Advanced Parameters": "التعليمات المتقدمة", "all": "الكل", - "All Documents": "", + "All Documents": "جميع الملفات", "All Users": "جميع المستخدمين", "Allow": "يسمح", "Allow Chat Deletion": "يستطيع حذف المحادثات", @@ -42,23 +42,23 @@ "API Key created.": "API تم أنشاء المفتاح", "API keys": "API المفاتيح", "API RPM": "API RPM", - "April": "", + "April": "أبريل", "Archive": "الأرشيف", "Archived Chats": "الأرشيف المحادثات", "are allowed - Activate this command by typing": "مسموح - قم بتنشيط هذا الأمر عن طريق الكتابة", "Are you sure?": "هل أنت متأكد ؟", - "Attach file": "", + "Attach file": "أرفق ملف", "Attention to detail": "انتبه للتفاصيل", "Audio": "صوتي", - "August": "", + "August": "أغسطس", "Auto-playback response": "استجابة التشغيل التلقائي", - "Auto-send input after 3 sec.": "إرسال تلقائي للإدخال بعد 3 ثوانٍ.", + "Auto-send input after 3 sec.": "إرسال تلقائي للإدخال بعد 3 ثواني.", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 الرابط الرئيسي", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 الرابط مطلوب", "available!": "متاح", "Back": "خلف", "Bad Response": "استجابة خطاء", - "before": "", + "before": "قبل", "Being lazy": "كون كسول", "Builder Mode": "بناء الموديل", "Bypass SSL verification for Websites": "", @@ -67,7 +67,7 @@ "Change Password": "تغير الباسورد", "Chat": "المحادثة", "Chat History": "تاريخ المحادثة", - "Chat History is off for this browser.": "سجل الدردشة معطل لهذا المتصفح.", + "Chat History is off for this browser.": "سجل الدردشة معطل لهذا المتصفح", "Chats": "المحادثات", "Check Again": "تحقق مرة اخرى", "Check for updates": "تحقق من التحديثات", @@ -78,11 +78,11 @@ "Chunk Size": "Chunk حجم", "Citation": "", "Click here for help.": "أضغط هنا للمساعدة", - "Click here to": "", - "Click here to check other modelfiles.": "انقر هنا للتحقق من ملفات الموديلات الأخرى.", + "Click here to": "أضغط هنا الانتقال", + "Click here to check other modelfiles.": "انقر هنا للتحقق من ملفات الموديلات الأخرى", "Click here to select": "أضغط هنا للاختيار", "Click here to select a csv file.": "أضغط هنا للاختيار ملف csv", - "Click here to select documents.": "انقر هنا لاختيار المستندات.", + "Click here to select documents.": "انقر هنا لاختيار المستندات", "click here.": "أضغط هنا", "Click on the user role button to change a user's role.": "أضغط على أسم الصلاحيات لتغيرها للمستخدم", "Close": "أغلق", @@ -97,17 +97,17 @@ "Context Length": "طول السياق", "Continue Response": "متابعة الرد", "Conversation Mode": "وضع المحادثة", - "Copied shared chat URL to clipboard!": "تم نسخ عنوان URL للدردشة المشتركة إلى الحافظة!", + "Copied shared chat URL to clipboard!": "تم نسخ عنوان URL للدردشة المشتركة إلى الحافظة", "Copy": "نسخ", "Copy last code block": "انسخ كتلة التعليمات البرمجية الأخيرة", "Copy last response": "انسخ الرد الأخير", "Copy Link": "أنسخ الرابط", - "Copying to clipboard was successful!": "تم النسخ إلى الحافظة بنجاح!", + "Copying to clipboard was successful!": "تم النسخ إلى الحافظة بنجاح", "Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "قم بإنشاء عبارة موجزة مكونة من 3-5 كلمات كرأس للاستعلام التالي، مع الالتزام الصارم بالحد الأقصى لعدد الكلمات الذي يتراوح بين 3-5 كلمات وتجنب استخدام الكلمة 'عنوان':", "Create a modelfile": "إنشاء ملف نموذجي", "Create Account": "إنشاء حساب", - "Create new key": "", - "Create new secret key": "", + "Create new key": "عمل مفتاح جديد", + "Create new secret key": "عمل سر جديد", "Created at": "أنشئت في", "Created At": "أنشئت من", "Current Model": "الموديل المختار", @@ -115,27 +115,27 @@ "Custom": "مخصص", "Customize Ollama models for a specific purpose": "تخصيص الموديل Ollama لغرض محدد", "Dark": "مظلم", - "Dashboard": "", + "Dashboard": "لوحة التحكم", "Database": "قاعدة البيانات", "DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm", - "December": "", + "December": "ديسمبر", "Default": "الإفتراضي", - "Default (Automatic1111)": "الإفتراضي (Automatic1111)", - "Default (SentenceTransformers)": "الإفتراضي (SentenceTransformers)", - "Default (Web API)": "الإفتراضي (Web API)", + "Default (Automatic1111)": "(Automatic1111) الإفتراضي", + "Default (SentenceTransformers)": "(SentenceTransformers) الإفتراضي", + "Default (Web API)": "(Web API) الإفتراضي", "Default model updated": "الإفتراضي تحديث الموديل", "Default Prompt Suggestions": "الإفتراضي Prompt الاقتراحات", "Default User Role": "الإفتراضي صلاحيات المستخدم", "delete": "حذف", - "Delete": "حذف.", + "Delete": "حذف", "Delete a model": "حذف الموديل", "Delete chat": "حذف المحادثه", "Delete Chat": "حذف المحادثه.", - "Delete Chats": "حذ المحادثات", - "delete this link": "", + "Delete Chats": "حذف المحادثات", + "delete this link": "أحذف هذا الرابط", "Delete User": "حذف المستخدم", - "Deleted {{deleteModelTag}}": "حذف {{deleteModelTag}}", - "Deleted {{tagName}}": "حذف {{tagName}}", + "Deleted {{deleteModelTag}}": "{{deleteModelTag}} حذف", + "Deleted {{tagName}}": "{{tagName}} حذف", "Description": "وصف", "Didn't fully follow instructions": "لم أتبع التعليمات بشكل كامل", "Disabled": "تعطيل", @@ -152,7 +152,7 @@ "Don't have an account?": "ليس لديك حساب؟", "Don't like the style": "لا أحب النمط", "Download": "تحميل", - "Download canceled": "", + "Download canceled": "تم اللغاء التحميل", "Download Database": "تحميل قاعدة البيانات", "Drop any files here to add to the conversation": "أسقط أية ملفات هنا لإضافتها إلى المحادثة", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "e.g. '30s','10m'. الوحدات الزمنية الصالحة هي 's', 'm', 'h'.", @@ -170,15 +170,15 @@ "Enter {{role}} message here": "أدخل رسالة {{role}} هنا", "Enter Chunk Overlap": "أدخل Chunk المتداخل", "Enter Chunk Size": "أدخل Chunk الحجم", - "Enter Image Size (e.g. 512x512)": "أدخل حجم الصورة (e.g. 512x512)", - "Enter language codes": "", + "Enter Image Size (e.g. 512x512)": "(e.g. 512x512) أدخل حجم الصورة ", + "Enter language codes": "أدخل كود اللغة", "Enter LiteLLM API Base URL (litellm_params.api_base)": "أدخل عنوان URL الأساسي لواجهة برمجة تطبيقات LiteLLM (litellm_params.api_base)", "Enter LiteLLM API Key (litellm_params.api_key)": "أدخل مفتاح LiteLLM API (litellm_params.api_key)", "Enter LiteLLM API RPM (litellm_params.rpm)": "أدخل LiteLLM API RPM (litllm_params.rpm)", "Enter LiteLLM Model (litellm_params.model)": "أدخل LiteLLM الموديل (litellm_params.model)", "Enter Max Tokens (litellm_params.max_tokens)": "أدخل أكثر Tokens (litellm_params.max_tokens)", - "Enter model tag (e.g. {{modelTag}})": "أدخل الموديل تاق (e.g. {{modelTag}})", - "Enter Number of Steps (e.g. 50)": "أدخل عدد الخطوات (e.g. 50)", + "Enter model tag (e.g. {{modelTag}})": "(e.g. {{modelTag}}) أدخل الموديل تاق", + "Enter Number of Steps (e.g. 50)": "(e.g. 50) أدخل عدد الخطوات", "Enter Score": "أدخل النتيجة", "Enter stop sequence": "أدخل تسلسل التوقف", "Enter Top K": "Enter Top K", @@ -196,7 +196,7 @@ "Export Prompts": "مطالبات التصدير", "Failed to create API Key.": "فشل في إنشاء مفتاح API.", "Failed to read clipboard contents": "فشل في قراءة محتويات الحافظة", - "February": "", + "February": "فبراير", "Feel free to add specific details": "لا تتردد في إضافة تفاصيل محددة", "File Mode": "وضع الملف", "File not found.": "لم يتم العثور على الملف.", @@ -212,8 +212,8 @@ "Generation Info": "معلومات الجيل", "Good Response": "استجابة جيدة", "has no conversations.": "ليس لديه محادثات.", - "Hello, {{name}}": "مرحبا, {{name}}", - "Help": "", + "Hello, {{name}}": " {{name}} مرحبا", + "Help": "مساعدة", "Hide": "أخفاء", "Hide Additional Params": "إخفاء المعلمات الإضافية", "How can I help you today?": "كيف استطيع مساعدتك اليوم؟", @@ -229,12 +229,12 @@ "Include `--api` flag when running stable-diffusion-webui": "قم بتضمين علامة `-api` عند تشغيل Stable-diffusion-webui", "Input commands": "", "Interface": "واجهه المستخدم", - "Invalid Tag": "", - "January": "", + "Invalid Tag": "تاق غير صالحة", + "January": "يناير", "join our Discord for help.": "انضم إلى Discord للحصول على المساعدة.", "JSON": "JSON", - "July": "", - "June": "", + "July": "يوليو", + "June": "يونيو", "JWT Expiration": "JWT تجريبي", "JWT Token": "JWT Token", "Keep Alive": "Keep Alive", @@ -242,18 +242,18 @@ "Language": "اللغة", "Last Active": "آخر نشاط", "Light": "فاتح", - "Listening...": "جاري الاستماع...", - "LLMs can make mistakes. Verify important information.": "يمكن أن يرتكب LLM الأخطاء. التحقق من المعلومات الهامة.", - "Made by OpenWebUI Community": "تم إنشاؤه بواسطة مجتمع OpenWebUI", + "Listening...": "جاري الاستماع", + "LLMs can make mistakes. Verify important information.": "يمكن أن تصدر بعض الأخطاء. لذلك يجب التحقق من المعلومات المهمة", + "Made by OpenWebUI Community": "OpenWebUI تم إنشاؤه بواسطة مجتمع ", "Make sure to enclose them with": "تأكد من إرفاقها", - "Manage LiteLLM Models": "إدارة نماذج LiteLLM", + "Manage LiteLLM Models": "LiteLLM إدارة نماذج ", "Manage Models": "إدارة النماذج", - "Manage Ollama Models": "إدارة موديلات Ollama", + "Manage Ollama Models": "Ollama إدارة موديلات ", "March": "", "Max Tokens": "Max Tokens", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "يمكن تنزيل 3 نماذج كحد أقصى في وقت واحد. الرجاء معاودة المحاولة في وقت لاحق.", "May": "", - "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "", + "Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "لن تتم مشاركة الرسائل التي ترسلها بعد إنشاء الرابط الخاص بك. سيتمكن المستخدمون الذين لديهم عنوان URL من عرض الدردشة المشتركة.", "Minimum Score": "الحد الأدنى من النقاط", "Mirostat": "Mirostat", "Mirostat Eta": "Mirostat Eta", @@ -263,7 +263,7 @@ "Model '{{modelName}}' has been successfully downloaded.": "موديل '{{modelName}}'تم تحميله بنجاح", "Model '{{modelTag}}' is already in queue for downloading.": "موديل '{{modelTag}}' جاري تحميلة الرجاء الانتظار", "Model {{modelId}} not found": "موديل {{modelId}} لم يوجد", - "Model {{modelName}} already exists.": "موديل {{modelName}} موجود", + "Model {{modelName}} already exists.": "موجود {{modelName}} موديل ", "Model filesystem path detected. Model shortname is required for update, cannot continue.": "تم اكتشاف مسار نظام الملفات النموذجي. الاسم المختصر للنموذج مطلوب للتحديث، ولا يمكن الاستمرار.", "Model Name": "أسم الموديل", "Model not selected": "لم تختار موديل", @@ -284,15 +284,15 @@ "Name your modelfile": "قم بتسمية ملف النموذج الخاص بك", "New Chat": "دردشة جديدة", "New Password": "كلمة المرور الجديدة", - "No results found": "", + "No results found": "لا توجد نتايج", "No source available": "", "Not factually correct": "ليس صحيحا من حيث الواقع", "Not sure what to add?": "لست متأكدا ما يجب إضافته؟", "Not sure what to write? Switch to": "لست متأكدا ماذا أكتب؟ التبديل إلى", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "ملاحظة: إذا قمت بتعيين الحد الأدنى من النقاط، فلن يؤدي البحث إلا إلى إرجاع المستندات التي لها نقاط أكبر من أو تساوي الحد الأدنى من النقاط.", "Notifications": "إشعارات", - "November": "", - "October": "", + "November": "نوفمبر", + "October": "اكتوبر", "Off": "أغلاق", "Okay, Let's Go!": "حسنا دعنا نذهب!", "OLED Dark": "OLED داكن", @@ -306,50 +306,50 @@ "Oops! Looks like the URL is invalid. Please double-check and try again.": "خطاء! يبدو أن عنوان URL غير صالح. يرجى التحقق مرة أخرى والمحاولة مرة أخرى.", "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "خطاء! أنت تستخدم طريقة غير مدعومة (الواجهة الأمامية فقط). يرجى تقديم واجهة WebUI من الواجهة الخلفية.", "Open": "فتح", - "Open AI": "فتح AI", - "Open AI (Dall-E)": "فتح AI (Dall-E)", + "Open AI": "AI فتح", + "Open AI (Dall-E)": "AI (Dall-E) فتح", "Open new chat": "فتح محادثة جديده", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", "OpenAI API Config": "OpenAI API إعدادات", - "OpenAI API Key is required.": "مطلوب مفتاح OpenAI API.", - "OpenAI URL/Key required.": "مطلوب عنوان URL/مفتاح OpenAI.", + "OpenAI API Key is required.": "OpenAI API.مطلوب مفتاح ", + "OpenAI URL/Key required.": "URL/مفتاح OpenAI.مطلوب عنوان ", "or": "أو", "Other": "آخر", - "Overview": "", + "Overview": "عرض", "Parameters": "Parameters", "Password": "الباسورد", "PDF document (.pdf)": "PDF ملف (.pdf)", "PDF Extract Images (OCR)": "PDF أستخرج الصور (OCR)", "pending": "قيد الانتظار", - "Permission denied when accessing microphone: {{error}}": "تم رفض الإذن عند الوصول إلى الميكروفون: {{error}}", + "Permission denied when accessing microphone: {{error}}": "{{error}} تم رفض الإذن عند الوصول إلى الميكروفون ", "Plain text (.txt)": "نص عادي (.txt)", "Playground": "مكان التجربة", "Positive attitude": "موقف ايجابي", - "Previous 30 days": "", - "Previous 7 days": "", + "Previous 30 days": "أخر 30 يوم", + "Previous 7 days": "أخر 7 أيام", "Profile Image": "صورة الملف الشخصي", - "Prompt": "", + "Prompt": "مطالبة", "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "موجه (على سبيل المثال: أخبرني بحقيقة ممتعة عن الإمبراطورية الرومانية)", "Prompt Content": "محتوى عاجل", "Prompt suggestions": "اقتراحات سريعة", - "Prompts": "حث", - "Pull \"{{searchValue}}\" from Ollama.com": "", - "Pull a model from Ollama.com": "سحب الموديل من Ollama.com", + "Prompts": "مطالبات", + "Pull \"{{searchValue}}\" from Ollama.com": "Ollama.com \"{{searchValue}}\" أسحب من ", + "Pull a model from Ollama.com": "Ollama.com سحب الموديل من ", "Pull Progress": "سحب التقدم", "Query Params": "Query Params", "RAG Template": "RAG تنمبلت", "Raw Format": "Raw فورمات", "Read Aloud": "أقراء لي", "Record voice": "سجل صوت", - "Redirecting you to OpenWebUI Community": "إعادة توجيهك إلى مجتمع OpenWebUI", + "Redirecting you to OpenWebUI Community": "OpenWebUI إعادة توجيهك إلى مجتمع ", "Refused when it shouldn't have": "رفض عندما لا ينبغي أن يكون", "Regenerate": "تجديد", "Release Notes": "ملاحظات الإصدار", "Remove": "إزالة", - "Remove Model": "", - "Rename": "", - "Repeat Last N": "كرر آخر N", + "Remove Model": "حذف الموديل", + "Rename": "إعادة تسمية", + "Repeat Last N": "N كرر آخر", "Repeat Penalty": "كرر المخالفة", "Request Mode": "وضع الطلب", "Reranking Model": "", @@ -367,21 +367,21 @@ "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "لم يعد حفظ سجلات الدردشة مباشرة في مساحة تخزين متصفحك مدعومًا. يرجى تخصيص بعض الوقت لتنزيل وحذف سجلات الدردشة الخاصة بك عن طريق النقر على الزر أدناه. لا تقلق، يمكنك بسهولة إعادة استيراد سجلات الدردشة الخاصة بك إلى الواجهة الخلفية من خلاله", "Scan": "مسح", "Scan complete!": "تم المسح", - "Scan for documents from {{path}}": " مسح على الملفات من {{path}}", + "Scan for documents from {{path}}": "{{path}} مسح على الملفات من", "Search": "البحث", "Search a model": "البحث عن موديل", "Search Documents": "البحث المستندات", "Search Prompts": "أبحث حث", - "See readme.md for instructions": "راجع readme.md للحصول على التعليمات", + "See readme.md for instructions": "readme.md للحصول على التعليمات", "See what's new": "ما الجديد", "Seed": "Seed", "Select a mode": "أختار موديل", "Select a model": "أختار الموديل", - "Select an Ollama instance": "أختار سيرفر Ollama", - "Select model": "", - "Send a Message": "أرسل رسالة.", - "Send message": "أرسل رسالة", - "September": "", + "Select an Ollama instance": "أختار سيرفر ", + "Select model": " أختار موديل", + "Send a Message": "يُرجى إدخال طلبك هنا", + "Send message": "يُرجى إدخال طلبك هنا.", + "September": "سبتمبر", "Server connection verified": "تم التحقق من اتصال الخادم", "Set as default": "الافتراضي", "Set Default Model": "تفعيد الموديل الافتراضي", @@ -396,7 +396,7 @@ "Settings saved successfully!": "تم حفظ الاعدادات بنجاح", "Share": "كشاركة", "Share Chat": "مشاركة الدردشة", - "Share to OpenWebUI Community": "شارك في مجتمع OpenWebUI", + "Share to OpenWebUI Community": "OpenWebUI شارك في مجتمع", "short-summary": "ملخص قصير", "Show": "عرض", "Show Additional Params": "إظهار المعلمات الإضافية", @@ -408,16 +408,16 @@ "Sign up": "تسجيل", "Signing in": "جاري الدخول", "Source": "", - "Speech recognition error: {{error}}": "خطأ في التعرف على الكلام: {{error}}", + "Speech recognition error: {{error}}": "{{error}} خطأ في التعرف على الكلام", "Speech-to-Text Engine": "محرك تحويل الكلام إلى نص", "SpeechRecognition API is not supported in this browser.": "API SpeechRecognition غير مدعومة في هذا المتصفح.", "Stop Sequence": "وقف التسلسل", "STT Settings": "STT اعدادات", "Submit": "إرسال", - "Subtitle (e.g. about the Roman Empire)": "الترجمة (e.g. about the Roman Empire)", + "Subtitle (e.g. about the Roman Empire)": "(e.g. about the Roman Empire) الترجمة", "Success": "نجاح", - "Successfully updated.": "تم التحديث بنجاح.", - "Suggested": "", + "Successfully updated.": "تم التحديث بنجاح", + "Suggested": "مقترحات", "Sync All": "مزامنة الكل", "System": "النظام", "System Prompt": "محادثة النظام", @@ -436,33 +436,33 @@ "Thorough explanation": "شرح شامل", "Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "ملاحضة: قم بتحديث عدة فتحات متغيرة على التوالي عن طريق الضغط على مفتاح tab في مدخلات الدردشة بعد كل استبدال.", "Title": "العنوان", - "Title (e.g. Tell me a fun fact)": "العناون (e.g. Tell me a fun fact)", + "Title (e.g. Tell me a fun fact)": "(e.g. Tell me a fun fact) العناون", "Title Auto-Generation": "توليد تلقائي للعنوان", - "Title cannot be an empty string.": "", + "Title cannot be an empty string.": "العنوان مطلوب", "Title Generation Prompt": "موجه إنشاء العنوان", "to": "الى", "To access the available model names for downloading,": "للوصول إلى أسماء الموديلات المتاحة للتنزيل،", "To access the GGUF models available for downloading,": "للوصول إلى الموديلات GGUF المتاحة للتنزيل،", "to chat input.": "الى كتابة المحادثه", - "Today": "", + "Today": "اليوم", "Toggle settings": "فتح وأغلاق الاعدادات", "Toggle sidebar": "فتح وأغلاق الشريط الجانبي", "Top K": "Top K", "Top P": "Top P", - "Trouble accessing Ollama?": "هل تواجه مشكلة في الوصول إلى Olma؟", + "Trouble accessing Ollama?": "هل تواجه مشكلة في الوصول", "TTS Settings": "TTS اعدادات", "Type Hugging Face Resolve (Download) URL": "اكتب عنوان URL لحل مشكلة الوجه (تنزيل).", - "Uh-oh! There was an issue connecting to {{provider}}.": "خطاء أوه! حدثت مشكلة في الاتصال بـ {{provider}}.", + "Uh-oh! There was an issue connecting to {{provider}}.": "{{provider}}خطاء أوه! حدثت مشكلة في الاتصال بـ ", "Unknown File Type '{{file_type}}', but accepting and treating as plain text": "نوع ملف غير معروف '{{file_type}}', ولكن القبول والتعامل كنص عادي ", "Update and Copy Link": "تحديث ونسخ الرابط", "Update password": "تحديث كلمة المرور", - "Upload a GGUF model": "رفع موديل نوع GGUF", + "Upload a GGUF model": "GGUF رفع موديل نوع", "Upload files": "رفع الملفات", "Upload Progress": "جاري التحميل", "URL Mode": "رابط الموديل", "Use '#' in the prompt input to load and select your documents.": "أستخدم '#' في المحادثة لربطهامن المستندات", - "Use Gravatar": "أستخدم Gravatar", - "Use Initials": "أستخدم Initials", + "Use Gravatar": "Gravatar أستخدم", + "Use Initials": "Initials أستخدم", "user": "مستخدم", "User Permissions": "صلاحيات المستخدم", "Users": "المستخدمين", @@ -483,13 +483,13 @@ "When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "عند إيقاف تشغيل السجل، لن تظهر الدردشات الجديدة على هذا المتصفح في سجلك على أي من أجهزتك.", "Whisper (Local)": "Whisper (Local)", "Write a prompt suggestion (e.g. Who are you?)": "اكتب اقتراحًا سريعًا (على سبيل المثال، من أنت؟)", - "Write a summary in 50 words that summarizes [topic or keyword].": "اكتب ملخصًا في 50 كلمة يلخص [الموضوع أو الكلمة الرئيسية].", - "Yesterday": "", + "Write a summary in 50 words that summarizes [topic or keyword].": "اكتب ملخصًا في 50 كلمة يلخص [الموضوع أو الكلمة الرئيسية]", + "Yesterday": "أمس", "You": "أنت", - "You have no archived conversations.": "", - "You have shared this chat": "", + "You have no archived conversations.": "لا تملك محادثات محفوظه", + "You have shared this chat": "تم مشاركة هذه المحادثة", "You're a helpful assistant.": "مساعدك المفيد هنا", "You're now logged in.": "لقد قمت الآن بتسجيل الدخول.", "Youtube": "Youtube", "Youtube Loader Settings": "" -} +} \ No newline at end of file From 1114f9625b70a62e01fa409a5c64e4ebdf74c0b3 Mon Sep 17 00:00:00 2001 From: HAMAD ABDULLA Date: Tue, 14 May 2024 01:59:17 +0300 Subject: [PATCH 28/29] Update translation.json --- src/lib/i18n/locales/ar-BH/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index 28508f8b5..c6af80d40 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -492,4 +492,4 @@ "You're now logged in.": "لقد قمت الآن بتسجيل الدخول.", "Youtube": "Youtube", "Youtube Loader Settings": "" -} \ No newline at end of file +} From 5369023e34396fba24a53bfb39baecb3c75e7b9e Mon Sep 17 00:00:00 2001 From: Jun Siang Cheah Date: Tue, 14 May 2024 14:30:15 +0800 Subject: [PATCH 29/29] fix: rag, chat deletion, and webhook after config persistence change --- backend/apps/openai/main.py | 6 +++--- backend/apps/web/routers/chats.py | 4 ++-- backend/main.py | 8 ++++---- src/routes/+layout.svelte | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/backend/apps/openai/main.py b/backend/apps/openai/main.py index fb16a579b..65ed25f1c 100644 --- a/backend/apps/openai/main.py +++ b/backend/apps/openai/main.py @@ -119,9 +119,9 @@ async def speech(request: Request, user=Depends(get_verified_user)): headers = {} headers["Authorization"] = f"Bearer {app.state.config.OPENAI_API_KEYS[idx]}" headers["Content-Type"] = "application/json" - if "openrouter.ai" in app.state.OPENAI_API_BASE_URLS[idx]: - headers['HTTP-Referer'] = "https://openwebui.com/" - headers['X-Title'] = "Open WebUI" + if "openrouter.ai" in app.state.config.OPENAI_API_BASE_URLS[idx]: + headers["HTTP-Referer"] = "https://openwebui.com/" + headers["X-Title"] = "Open WebUI" r = None try: r = requests.post( diff --git a/backend/apps/web/routers/chats.py b/backend/apps/web/routers/chats.py index f72ed79b3..aaf173521 100644 --- a/backend/apps/web/routers/chats.py +++ b/backend/apps/web/routers/chats.py @@ -58,7 +58,7 @@ async def delete_all_user_chats(request: Request, user=Depends(get_current_user) if ( user.role == "user" - and not request.app.state.USER_PERMISSIONS["chat"]["deletion"] + and not request.app.state.config.USER_PERMISSIONS["chat"]["deletion"] ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -266,7 +266,7 @@ async def delete_chat_by_id(request: Request, id: str, user=Depends(get_current_ result = Chats.delete_chat_by_id(id) return result else: - if not request.app.state.USER_PERMISSIONS["chat"]["deletion"]: + if not request.app.state.config.USER_PERMISSIONS["chat"]["deletion"]: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, diff --git a/backend/main.py b/backend/main.py index 8b7f9af69..e3031e793 100644 --- a/backend/main.py +++ b/backend/main.py @@ -144,12 +144,12 @@ class RAGMiddleware(BaseHTTPMiddleware): data["messages"], citations = rag_messages( docs=data["docs"], messages=data["messages"], - template=rag_app.state.RAG_TEMPLATE, + template=rag_app.state.config.RAG_TEMPLATE, embedding_function=rag_app.state.EMBEDDING_FUNCTION, - k=rag_app.state.TOP_K, + k=rag_app.state.config.TOP_K, reranking_function=rag_app.state.sentence_transformer_rf, - r=rag_app.state.RELEVANCE_THRESHOLD, - hybrid_search=rag_app.state.ENABLE_RAG_HYBRID_SEARCH, + r=rag_app.state.config.RELEVANCE_THRESHOLD, + hybrid_search=rag_app.state.config.ENABLE_RAG_HYBRID_SEARCH, ) del data["docs"] diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 5a8a8bba3..dd90caa27 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -24,9 +24,9 @@ let backendConfig = null; try { backendConfig = await getBackendConfig(); - console.log("Backend config:", backendConfig); + console.log('Backend config:', backendConfig); } catch (error) { - console.error("Error loading backend config:", error); + console.error('Error loading backend config:', error); } // Initialize i18n even if we didn't get a backend config, // so `/error` can show something that's not `undefined`.