Unverified Commit 5166e92f authored by arkohut's avatar arkohut Committed by GitHub
Browse files

Merge branch 'dev' into support-py-for-run-code

parents b443d61c b6b71c08
......@@ -3,6 +3,8 @@
"(Beta)": "(бета)",
"(e.g. `sh webui.sh --api`)": "(нпр. `sh webui.sh --api`)",
"(latest)": "(најновије)",
"{{ models }}": "",
"{{ owner }}: You cannot delete a base model": "",
"{{modelName}} is thinking...": "{{modelName}} размишља...",
"{{user}}'s Chats": "Ћаскања корисника {{user}}",
"{{webUIName}} Backend Required": "Захтева се {{webUIName}} позадинац",
......@@ -10,16 +12,15 @@
"About": "О нама",
"Account": "Налог",
"Accurate information": "Прецизне информације",
"Add": "",
"Add a model": "Додај модел",
"Add a model tag name": "Додај ознаку модела",
"Add a short description about what this modelfile does": "Додај кратак опис ове модел-датотеке",
"Add": "Додај",
"Add a model id": "",
"Add a short description about what this model does": "",
"Add a short title for this prompt": "Додај кратак наслов за овај упит",
"Add a tag": "Додај ознаку",
"Add custom prompt": "Додај прилагођен упит",
"Add Docs": "Додај документе",
"Add Files": "Додај датотеке",
"Add Memory": "",
"Add Memory": "Додај меморију",
"Add message": "Додај поруку",
"Add Model": "Додај модел",
"Add Tags": "Додај ознаке",
......@@ -29,6 +30,7 @@
"Admin Panel": "Админ табла",
"Admin Settings": "Админ подешавања",
"Advanced Parameters": "Напредни параметри",
"Advanced Params": "",
"all": "сви",
"All Documents": "Сви документи",
"All Users": "Сви корисници",
......@@ -43,9 +45,9 @@
"API Key": "API кључ",
"API Key created.": "API кључ направљен.",
"API keys": "API кључеви",
"API RPM": "API RPM",
"April": "Април",
"Archive": "Архива",
"Archive All Chats": "",
"Archived Chats": "Архивирана ћаскања",
"are allowed - Activate this command by typing": "су дозвољени - Покрените ову наредбу уношењем",
"Are you sure?": "Да ли сте сигурни?",
......@@ -60,12 +62,13 @@
"available!": "доступно!",
"Back": "Назад",
"Bad Response": "Лош одговор",
"Banners": "",
"Base Model (From)": "",
"before": "пре",
"Being lazy": "Бити лењ",
"Builder Mode": "Режим градитеља",
"Bypass SSL verification for Websites": "Заобиђи SSL потврђивање за веб странице",
"Cancel": "Откажи",
"Categories": "Категорије",
"Capabilities": "",
"Change Password": "Промени лозинку",
"Chat": "Ћаскање",
"Chat Bubble UI": "Интерфејс балона ћаскања",
......@@ -83,7 +86,6 @@
"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.": "Кликните овде да изаберете документе.",
......@@ -108,7 +110,7 @@
"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 a model": "",
"Create Account": "Направи налог",
"Create new key": "Направи нови кључ",
"Create new secret key": "Направи нови тајни кључ",
......@@ -117,9 +119,8 @@
"Current Model": "Тренутни модел",
"Current Password": "Тренутна лозинка",
"Custom": "Прилагођено",
"Customize Ollama models for a specific purpose": "Прилагоди Ollama моделе за специфичну намену",
"Customize models for a specific purpose": "",
"Dark": "Тамна",
"Dashboard": "Контролна табла",
"Database": "База података",
"December": "Децембар",
"Default": "Подразумевано",
......@@ -132,17 +133,17 @@
"delete": "обриши",
"Delete": "Обриши",
"Delete a model": "Обриши модел",
"Delete All Chats": "",
"Delete chat": "Обриши ћаскање",
"Delete Chat": "Обриши ћаскање",
"Delete Chats": "Обриши ћаскања",
"delete this link": "обриши ову везу",
"Delete User": "Обриши корисника",
"Deleted {{deleteModelTag}}": "Обрисано {{deleteModelTag}}",
"Deleted {{tagName}}": "Обрисано {{tagName}}",
"Deleted {{name}}": "",
"Description": "Опис",
"Didn't fully follow instructions": "Упутства нису праћена у потпуности",
"Disabled": "Онемогућено",
"Discover a modelfile": "Откриј модел-датотеку",
"Discover a model": "",
"Discover a prompt": "Откриј упит",
"Discover, download, and explore custom prompts": "Откријте, преузмите и истражите прилагођене упите",
"Discover, download, and explore model presets": "Откријте, преузмите и истражите образце модела",
......@@ -171,16 +172,11 @@
"Enabled": "Омогућено",
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Уверите се да ваша CSV датотека укључује 4 колоне у овом редоследу: Име, Е-пошта, Лозинка, Улога.",
"Enter {{role}} message here": "Унесите {{role}} поруку овде",
"Enter a detail about yourself for your LLMs to recall": "",
"Enter a detail about yourself for your LLMs to recall": "Унесите детаље за себе да ће LLMs преузимати",
"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 LiteLLM API (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 (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": "Унесите резултат",
......@@ -192,11 +188,12 @@
"Enter Your Full Name": "Унесите ваше име и презиме",
"Enter Your Password": "Унесите вашу лозинку",
"Enter Your Role": "Унесите вашу улогу",
"Error": "",
"Experimental": "Експериментално",
"Export All Chats (All Users)": "Извези сва ћаскања (сви корисници)",
"Export Chats": "Извези ћаскања",
"Export Documents Mapping": "Извези мапирање докумената",
"Export Modelfiles": "Извези модел-датотеке",
"Export Models": "",
"Export Prompts": "Извези упите",
"Failed to create API Key.": "Неуспешно стварање API кључа.",
"Failed to read clipboard contents": "Неуспешно читање садржаја оставе",
......@@ -209,7 +206,7 @@
"Focus chat input": "Усредсредите унос ћаскања",
"Followed instructions perfectly": "Упутства су савршено праћена",
"Format your variables using square brackets like this:": "Форматирајте ваше променљиве користећи угластe заграде овако:",
"From (Base Model)": "Од (основни модел)",
"Frequencey Penalty": "",
"Full Screen Mode": "Режим целог екрана",
"General": "Опште",
"General Settings": "Општа подешавања",
......@@ -220,7 +217,6 @@
"Hello, {{name}}": "Здраво, {{name}}",
"Help": "Помоћ",
"Hide": "Сакриј",
"Hide Additional Params": "Сакриј додатне параметре",
"How can I help you today?": "Како могу да вам помогнем данас?",
"Hybrid Search": "Хибридна претрага",
"Image Generation (Experimental)": "Стварање слика (експериментално)",
......@@ -229,15 +225,17 @@
"Images": "Слике",
"Import Chats": "Увези ћаскања",
"Import Documents Mapping": "Увези мапирање докумената",
"Import Modelfiles": "Увези модел-датотеке",
"Import Models": "",
"Import Prompts": "Увези упите",
"Include `--api` flag when running stable-diffusion-webui": "Укључи `--api` заставицу при покретању stable-diffusion-webui",
"Info": "",
"Input commands": "Унеси наредбе",
"Interface": "Изглед",
"Invalid Tag": "Неисправна ознака",
"January": "Јануар",
"join our Discord for help.": "придружите се нашем Дискорду за помоћ.",
"JSON": "JSON",
"JSON Preview": "",
"July": "Јул",
"June": "Јун",
"JWT Expiration": "Истек JWT-а",
......@@ -252,14 +250,13 @@
"LTR": "ЛНД",
"Made by OpenWebUI Community": "Израдила OpenWebUI заједница",
"Make sure to enclose them with": "Уверите се да их затворите са",
"Manage LiteLLM Models": "Управљај LiteLLM моделима",
"Manage Models": "Управљај моделима",
"Manage Ollama Models": "Управљај Ollama моделима",
"March": "Март",
"Max Tokens": "Највише жетона",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Највише 3 модела могу бити преузета истовремено. Покушајте поново касније.",
"May": "Мај",
"Memories accessible by LLMs will be shown here.": "",
"Memories accessible by LLMs will be shown here.": "Памћења које ће бити појављена од овог LLM-а ће бити приказана овде.",
"Memory": "Памћење",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Поруке које пошаљете након стварања ваше везе неће бити подељене. Корисници са URL-ом ће моћи да виде дељено ћаскање.",
"Minimum Score": "Најмањи резултат",
......@@ -271,29 +268,24 @@
"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}} is not vision capable": "",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Откривена путања система датотека модела. За ажурирање је потребан кратак назив модела, не може се наставити.",
"Model Name": "Назив модела",
"Model ID": "",
"Model not selected": "Модел није изабран",
"Model Tag Name": "Назив ознаке модела",
"Model Params": "",
"Model Whitelisting": "Бели списак модела",
"Model(s) Whitelisted": "Модел(и) на белом списку",
"Modelfile": "Модел-датотека",
"Modelfile Advanced Settings": "Напредна подешавања модел-датотеке",
"Modelfile Content": "Садржај модел-датотеке",
"Modelfiles": "Модел-датотеке",
"Models": "Модели",
"More": "Више",
"Name": "Име",
"Name Tag": "Назив ознаке",
"Name your modelfile": "Назовите вашу модел-датотеку",
"Name your model": "",
"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": "Новембар",
......@@ -302,7 +294,7 @@
"Okay, Let's Go!": "У реду, хајде да кренемо!",
"OLED Dark": "OLED тамна",
"Ollama": "Ollama",
"Ollama Base URL": "Основна адреса Ollama-е",
"Ollama API": "",
"Ollama Version": "Издање Ollama-е",
"On": "Укључено",
"Only": "Само",
......@@ -321,8 +313,6 @@
"OpenAI URL/Key required.": "Потребан је OpenAI URL/кључ.",
"or": "или",
"Other": "Остало",
"Overview": "Преглед",
"Parameters": "Параметри",
"Password": "Лозинка",
"PDF document (.pdf)": "PDF документ (.pdf)",
"PDF Extract Images (OCR)": "Извлачење PDF слика (OCR)",
......@@ -342,10 +332,8 @@
"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 заједницу",
......@@ -356,7 +344,6 @@
"Remove Model": "Уклони модел",
"Rename": "Преименуј",
"Repeat Last N": "Понови последњих N",
"Repeat Penalty": "Казна за понављање",
"Request Mode": "Режим захтева",
"Reranking Model": "Модел поновног рангирања",
"Reranking model disabled": "Модел поновног рангирања онемогућен",
......@@ -376,15 +363,19 @@
"Scan for documents from {{path}}": "Скенирај документе из {{path}}",
"Search": "Претражи",
"Search a model": "Претражи модел",
"Search Chats": "",
"Search Documents": "Претражи документе",
"Search Models": "",
"Search Prompts": "Претражи упите",
"See readme.md for instructions": "Погледај readme.md за упутства",
"See what's new": "Погледај шта је ново",
"Seed": "Семе",
"Select a base model": "",
"Select a mode": "Изабери режим",
"Select a model": "Изабери модел",
"Select an Ollama instance": "Изабери Ollama инстанцу",
"Select model": "Изабери модел",
"Selected model(s) do not support image inputs": "",
"Send": "Пошаљи",
"Send a Message": "Пошаљи поруку",
"Send message": "Пошаљи поруку",
......@@ -406,7 +397,6 @@
"Share to OpenWebUI Community": "Подели са OpenWebUI заједницом",
"short-summary": "кратак сажетак",
"Show": "Прикажи",
"Show Additional Params": "Прикажи додатне параметре",
"Show shortcuts": "Прикажи пречице",
"Showcased creativity": "Приказана креативност",
"sidebar": "бочна трака",
......@@ -425,7 +415,6 @@
"Success": "Успех",
"Successfully updated.": "Успешно ажурирано.",
"Suggested": "Предложено",
"Sync All": "Усклади све",
"System": "Систем",
"System Prompt": "Системски упит",
"Tags": "Ознаке",
......@@ -458,6 +447,7 @@
"Top P": "Топ П",
"Trouble accessing Ollama?": "Проблеми са приступом Ollama-и?",
"TTS Settings": "TTS подешавања",
"Type": "",
"Type Hugging Face Resolve (Download) URL": "Унесите Hugging Face Resolve (Download) адресу",
"Uh-oh! There was an issue connecting to {{provider}}.": "Упс! Дошло је до проблема при повезивању са {{provider}}.",
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Непознат тип датотеке '{{file_type}}', али прихваћен и третиран као обичан текст",
......@@ -478,6 +468,7 @@
"variable": "променљива",
"variable to have them replaced with clipboard content.": "променљива за замену са садржајем оставе.",
"Version": "Издање",
"Warning": "",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "Упозорење: ако ажурирате или промените ваш модел уградње, мораћете поново да увезете све документе.",
"Web": "Веб",
"Web Loader Settings": "Подешавања веб учитавача",
......@@ -494,6 +485,7 @@
"Write a summary in 50 words that summarizes [topic or keyword].": "Напишите сажетак у 50 речи који резимира [тему или кључну реч].",
"Yesterday": "Јуче",
"You": "Ти",
"You cannot clone a base model": "",
"You have no archived conversations.": "Немате архивиране разговоре.",
"You have shared this chat": "Поделили сте ово ћаскање",
"You're a helpful assistant.": "Ти си користан помоћник.",
......
......@@ -3,34 +3,36 @@
"(Beta)": "(Beta)",
"(e.g. `sh webui.sh --api`)": "(t.ex. `sh webui.sh --api`)",
"(latest)": "(senaste)",
"{{ models }}": "",
"{{ owner }}: You cannot delete a base model": "",
"{{modelName}} is thinking...": "{{modelName}} tänker...",
"{{user}}'s Chats": "",
"{{user}}'s Chats": "{{user}}s Chats",
"{{webUIName}} Backend Required": "{{webUIName}} Backend krävs",
"a user": "en användare",
"About": "Om",
"Account": "Konto",
"Accurate information": "",
"Add": "",
"Add a model": "Lägg till en modell",
"Add a model tag name": "Lägg till ett modellnamn",
"Add a short description about what this modelfile does": "Lägg till en kort beskrivning av vad den här modelfilen gör",
"Accurate information": "Exakt information",
"Add": "Lägg till",
"Add a model id": "",
"Add a short description about what this model does": "",
"Add a short title for this prompt": "Lägg till en kort titel för denna prompt",
"Add a tag": "Lägg till en tagg",
"Add custom prompt": "Lägg till en anpassad prompt",
"Add Docs": "Lägg till dokument",
"Add Files": "Lägg till filer",
"Add Memory": "",
"Add Memory": "Lägg till minne",
"Add message": "Lägg till meddelande",
"Add Model": "",
"Add Tags": "",
"Add User": "",
"Add Model": "Lägg till modell",
"Add Tags": "Lägg till taggar",
"Add User": "Lägg till användare",
"Adjusting these settings will apply changes universally to all users.": "Justering av dessa inställningar kommer att tillämpa ändringar universellt för alla användare.",
"admin": "administratör",
"Admin Panel": "Administrationspanel",
"Admin Settings": "Administratörsinställningar",
"Advanced Parameters": "Avancerade parametrar",
"Advanced Params": "",
"all": "alla",
"All Documents": "",
"All Documents": "Alla dokument",
"All Users": "Alla användare",
"Allow": "Tillåt",
"Allow Chat Deletion": "Tillåt chattborttagning",
......@@ -38,38 +40,39 @@
"Already have an account?": "Har du redan ett konto?",
"an assistant": "en assistent",
"and": "och",
"and create a new shared link.": "",
"and create a new shared link.": "och skapa en ny delad länk.",
"API Base URL": "API-bas-URL",
"API Key": "API-nyckel",
"API Key created.": "",
"API keys": "",
"API RPM": "API RPM",
"April": "",
"Archive": "",
"Archived Chats": "",
"API Key created.": "API-nyckel skapad.",
"API keys": "API-nycklar",
"April": "April",
"Archive": "Arkiv",
"Archive All Chats": "",
"Archived Chats": "Arkiverade chattar",
"are allowed - Activate this command by typing": "är tillåtna - Aktivera detta kommando genom att skriva",
"Are you sure?": "Är du säker?",
"Attach file": "Bifoga fil",
"Attention to detail": "Detaljerad uppmärksamhet",
"Audio": "Ljud",
"August": "",
"August": "Augusti",
"Auto-playback response": "Automatisk uppspelning",
"Auto-send input after 3 sec.": "Skicka automatiskt indata efter 3 sek.",
"AUTOMATIC1111 Base URL": "AUTOMATIC1111 bas-URL",
"AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 bas-URL krävs.",
"available!": "tillgänglig!",
"Back": "Tillbaka",
"Bad Response": "",
"before": "",
"Being lazy": "",
"Builder Mode": "Byggarläge",
"Bypass SSL verification for Websites": "",
"Bad Response": "Felaktig respons",
"Banners": "",
"Base Model (From)": "",
"before": "før",
"Being lazy": "Lägg till",
"Bypass SSL verification for Websites": "Kringgå SSL-verifiering för webbplatser",
"Cancel": "Avbryt",
"Categories": "Kategorier",
"Capabilities": "",
"Change Password": "Ändra lösenord",
"Chat": "Chatt",
"Chat Bubble UI": "",
"Chat direction": "",
"Chat Bubble UI": "Chatbubblar UI",
"Chat direction": "Chattriktning",
"Chat History": "Chatthistorik",
"Chat History is off for this browser.": "Chatthistoriken är avstängd för denna webbläsare.",
"Chats": "Chattar",
......@@ -82,67 +85,65 @@
"Chunk Size": "Chunk-storlek",
"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.",
"Click here to": "Klicka här för att",
"Click here to select": "Klicka här för att välja",
"Click here to select a csv file.": "",
"Click here to select a csv file.": "Klicka här för att välja en csv-fil.",
"Click here to select documents.": "Klicka här för att välja dokument.",
"click here.": "klicka här.",
"Click on the user role button to change a user's role.": "Klicka på knappen för användarroll för att ändra en användares roll.",
"Close": "Stäng",
"Collection": "Samling",
"ComfyUI": "",
"ComfyUI Base URL": "",
"ComfyUI Base URL is required.": "",
"ComfyUI": "ComfyUI",
"ComfyUI Base URL": "ComfyUI Base URL",
"ComfyUI Base URL is required.": "ComfyUI Base URL krävs.",
"Command": "Kommando",
"Confirm Password": "Bekräfta lösenord",
"Connections": "Anslutningar",
"Content": "Innehåll",
"Context Length": "Kontextlängd",
"Continue Response": "",
"Continue Response": "Fortsätt svar",
"Conversation Mode": "Samtalsläge",
"Copied shared chat URL to clipboard!": "",
"Copy": "",
"Copied shared chat URL to clipboard!": "Kopierad delad chatt-URL till urklipp!",
"Copy": "Kopiera",
"Copy last code block": "Kopiera sista kodblock",
"Copy last response": "Kopiera sista svar",
"Copy Link": "",
"Copy Link": "Kopiera länk",
"Copying to clipboard was successful!": "Kopiering till urklipp lyckades!",
"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':": "Skapa en kort, 3-5 ords fras som rubrik för följande fråga, strikt följa 3-5 ordsgränsen och undvika användning av ordet 'titel':",
"Create a modelfile": "Skapa en modelfil",
"Create a model": "",
"Create Account": "Skapa konto",
"Create new key": "",
"Create new secret key": "",
"Create new key": "Skapa ny nyckel",
"Create new secret key": "Skapa ny hemlig nyckel",
"Created at": "Skapad",
"Created At": "",
"Created At": "Skapad",
"Current Model": "Aktuell modell",
"Current Password": "Nuvarande lösenord",
"Custom": "Anpassad",
"Customize Ollama models for a specific purpose": "Anpassa Ollama-modeller för ett specifikt ändamål",
"Customize models for a specific purpose": "",
"Dark": "Mörk",
"Dashboard": "",
"Database": "Databas",
"December": "",
"December": "December",
"Default": "Standard",
"Default (Automatic1111)": "Standard (Automatic1111)",
"Default (SentenceTransformers)": "",
"Default (SentenceTransformers)": "Standard (SentenceTransformers)",
"Default (Web API)": "Standard (Web API)",
"Default model updated": "Standardmodell uppdaterad",
"Default Prompt Suggestions": "Standardpromptförslag",
"Default User Role": "Standardanvändarroll",
"delete": "radera",
"Delete": "",
"Delete": "Radera",
"Delete a model": "Ta bort en modell",
"Delete All Chats": "",
"Delete chat": "Radera chatt",
"Delete Chat": "",
"Delete Chats": "Radera chattar",
"delete this link": "",
"Delete User": "",
"Delete Chat": "Radera chatt",
"delete this link": "radera denna länk",
"Delete User": "Radera användare",
"Deleted {{deleteModelTag}}": "Raderad {{deleteModelTag}}",
"Deleted {{tagName}}": "",
"Deleted {{name}}": "",
"Description": "Beskrivning",
"Didn't fully follow instructions": "",
"Didn't fully follow instructions": "Följde inte instruktionerna",
"Disabled": "Inaktiverad",
"Discover a modelfile": "Upptäck en modelfil",
"Discover a model": "",
"Discover a prompt": "Upptäck en prompt",
"Discover, download, and explore custom prompts": "Upptäck, ladda ner och utforska anpassade prompts",
"Discover, download, and explore model presets": "Upptäck, ladda ner och utforska modellförinställningar",
......@@ -153,156 +154,147 @@
"does not make any external connections, and your data stays securely on your locally hosted server.": "gör inga externa anslutningar, och dina data förblir säkra på din lokalt värdade server.",
"Don't Allow": "Tillåt inte",
"Don't have an account?": "Har du inte ett konto?",
"Don't like the style": "",
"Download": "",
"Download canceled": "",
"Don't like the style": "Du tycker inte om utseendet",
"Download": "Ladda ner",
"Download canceled": "Nedladdning avbruten",
"Download Database": "Ladda ner databas",
"Drop any files here to add to the conversation": "Släpp filer här för att lägga till i konversationen",
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "t.ex. '30s', '10m'. Giltiga tidsenheter är 's', 'm', 'h'.",
"Edit": "",
"Edit": "Redigera",
"Edit Doc": "Redigera dokument",
"Edit User": "Redigera användare",
"Email": "E-post",
"Embedding Model": "",
"Embedding Model Engine": "",
"Embedding model set to \"{{embedding_model}}\"": "",
"Embedding Model": "Embeddingsmodell",
"Embedding Model Engine": "Embeddingsmodellmotor",
"Embedding model set to \"{{embedding_model}}\"": "Embeddingsmodell inställd på \"{{embedding_model}}\"",
"Enable Chat History": "Aktivera chatthistorik",
"Enable New Sign Ups": "Aktivera nya registreringar",
"Enabled": "Aktiverad",
"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.": "Se till att din CSV-fil innehåller fyra kolumner i denna ordning: Namn, E-post, Lösenord, Roll.",
"Enter {{role}} message here": "Skriv {{role}} meddelande här",
"Enter a detail about yourself for your LLMs to recall": "",
"Enter a detail about yourself for your LLMs to recall": "Skriv en detalj om dig själv för att dina LLMs ska komma ihåg",
"Enter Chunk Overlap": "Ange Chunk-överlappning",
"Enter Chunk Size": "Ange Chunk-storlek",
"Enter Image Size (e.g. 512x512)": "Ange bildstorlek (t.ex. 512x512)",
"Enter language codes": "",
"Enter LiteLLM API Base URL (litellm_params.api_base)": "Ange LiteLLM API-bas-URL (litellm_params.api_base)",
"Enter LiteLLM API Key (litellm_params.api_key)": "Ange LiteLLM API-nyckel (litellm_params.api_key)",
"Enter LiteLLM API RPM (litellm_params.rpm)": "Ange LiteLLM API RPM (litellm_params.rpm)",
"Enter LiteLLM Model (litellm_params.model)": "Ange LiteLLM-modell (litellm_params.model)",
"Enter Max Tokens (litellm_params.max_tokens)": "Ange max antal tokens (litellm_params.max_tokens)",
"Enter language codes": "Skriv språkkoder",
"Enter model tag (e.g. {{modelTag}})": "Ange modelltagg (t.ex. {{modelTag}})",
"Enter Number of Steps (e.g. 50)": "Ange antal steg (t.ex. 50)",
"Enter Score": "",
"Enter Score": "Ange poäng",
"Enter stop sequence": "Ange stoppsekvens",
"Enter Top K": "Ange Top K",
"Enter URL (e.g. http://127.0.0.1:7860/)": "Ange URL (t.ex. http://127.0.0.1:7860/)",
"Enter URL (e.g. http://localhost:11434)": "",
"Enter URL (e.g. http://localhost:11434)": "Ange URL (t.ex. http://localhost:11434)",
"Enter Your Email": "Ange din e-post",
"Enter Your Full Name": "Ange ditt fullständiga namn",
"Enter Your Password": "Ange ditt lösenord",
"Enter Your Role": "",
"Enter Your Role": "Ange din roll",
"Error": "",
"Experimental": "Experimentell",
"Export All Chats (All Users)": "Exportera alla chattar (alla användare)",
"Export Chats": "Exportera chattar",
"Export Documents Mapping": "Exportera dokumentmappning",
"Export Modelfiles": "Exportera modelfiler",
"Export Models": "",
"Export Prompts": "Exportera prompts",
"Failed to create API Key.": "",
"Failed to create API Key.": "Misslyckades med att skapa API-nyckel.",
"Failed to read clipboard contents": "Misslyckades med att läsa urklippsinnehåll",
"February": "",
"Feel free to add specific details": "",
"February": "Februar",
"Feel free to add specific details": "Förfoga att lägga till specifika detaljer",
"File Mode": "Fil-läge",
"File not found.": "Fil hittades inte.",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingeravtrycksmanipulering upptäckt: Kan inte använda initialer som avatar. Återställning till standardprofilbild.",
"Fluidly stream large external response chunks": "Flytande ström stora externa svarsblock",
"Focus chat input": "Fokusera chattindata",
"Followed instructions perfectly": "",
"Followed instructions perfectly": "Följde instruktionerna perfekt",
"Format your variables using square brackets like this:": "Formatera dina variabler med hakparenteser så här:",
"From (Base Model)": "Från (basmodell)",
"Frequencey Penalty": "",
"Full Screen Mode": "Helskärmsläge",
"General": "Allmän",
"General Settings": "Allmänna inställningar",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Generation Info": "Generasjon Info",
"Good Response": "Bra svar",
"h:mm a": "h:mm a",
"has no conversations.": "har ingen samtaler.",
"Hello, {{name}}": "Hej, {{name}}",
"Help": "",
"Help": "Hjelp",
"Hide": "Dölj",
"Hide Additional Params": "Dölj ytterligare parametrar",
"How can I help you today?": "Hur kan jag hjälpa dig idag?",
"Hybrid Search": "",
"Hybrid Search": "Hybrid sökning",
"Image Generation (Experimental)": "Bildgenerering (experimentell)",
"Image Generation Engine": "Bildgenereringsmotor",
"Image Settings": "Bildinställningar",
"Images": "Bilder",
"Import Chats": "Importera chattar",
"Import Documents Mapping": "Importera dokumentmappning",
"Import Modelfiles": "Importera modelfiler",
"Import Models": "",
"Import Prompts": "Importera prompts",
"Include `--api` flag when running stable-diffusion-webui": "Inkludera `--api`-flagga när du kör stabil-diffusion-webui",
"Info": "",
"Input commands": "Indatakommandon",
"Interface": "Gränssnitt",
"Invalid Tag": "",
"January": "",
"Invalid Tag": "Ogiltig tagg",
"January": "januar",
"join our Discord for help.": "gå med i vår Discord för hjälp.",
"JSON": "JSON",
"July": "",
"June": "",
"JSON Preview": "",
"July": "juli",
"June": "juni",
"JWT Expiration": "JWT-utgång",
"JWT Token": "JWT-token",
"Keep Alive": "Håll vid liv",
"Keyboard shortcuts": "Tangentbordsgenvägar",
"Language": "Språk",
"Last Active": "",
"Last Active": "Senast aktiv",
"Light": "Ljus",
"Listening...": "Lyssnar...",
"LLMs can make mistakes. Verify important information.": "LLM:er kan göra misstag. Verifiera viktig information.",
"LTR": "",
"LTR": "LTR",
"Made by OpenWebUI Community": "Skapad av OpenWebUI Community",
"Make sure to enclose them with": "Se till att bifoga dem med",
"Manage LiteLLM Models": "Hantera LiteLLM-modeller",
"Manage Models": "Hantera modeller",
"Manage Ollama Models": "Hantera Ollama-modeller",
"March": "",
"Max Tokens": "Max antal tokens",
"March": "mars",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Högst 3 modeller kan laddas ner samtidigt. Vänligen försök igen senare.",
"May": "",
"Memories accessible by LLMs will be shown here.": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "",
"Minimum Score": "",
"May": "mai",
"Memories accessible by LLMs will be shown here.": "Minnen som kan komma ihåg av LLM:er kommer att visas här.",
"Memory": "Minnen",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Meddelanden du skickar efter att ha skapat din länk kommer inte att delas. Användare med URL:en kommer att kunna se delad chatt.",
"Minimum Score": "Minimum poäng",
"Mirostat": "Mirostat",
"Mirostat Eta": "Mirostat Eta",
"Mirostat Tau": "Mirostat Tau",
"MMMM DD, YYYY": "MMMM DD, ÅÅÅÅ",
"MMMM DD, YYYY HH:mm": "",
"MMMM DD, YYYY HH:mm": "MMMM DD, ÅÅÅÅ HH:mm",
"Model '{{modelName}}' has been successfully downloaded.": "Modellen '{{modelName}}' har laddats ner framgångsrikt.",
"Model '{{modelTag}}' is already in queue for downloading.": "Modellen '{{modelTag}}' är redan i kö för nedladdning.",
"Model {{modelId}} not found": "Modell {{modelId}} hittades inte",
"Model {{modelName}} already exists.": "Modellen {{modelName}} finns redan.",
"Model {{modelName}} is not vision capable": "",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Modellens filsystemväg upptäckt. Modellens kortnamn krävs för uppdatering, kan inte fortsätta.",
"Model Name": "Modellnamn",
"Model ID": "",
"Model not selected": "Modell inte vald",
"Model Tag Name": "Modelltaggnamn",
"Model Params": "",
"Model Whitelisting": "Modellens vitlista",
"Model(s) Whitelisted": "Modell(er) vitlistade",
"Modelfile": "Modelfil",
"Modelfile Advanced Settings": "Modelfilens avancerade inställningar",
"Modelfile Content": "Modelfilens innehåll",
"Modelfiles": "Modelfiler",
"Models": "Modeller",
"More": "",
"More": "Mer",
"Name": "Namn",
"Name Tag": "Namntag",
"Name your modelfile": "Namnge din modelfil",
"Name your model": "",
"New Chat": "Ny chatt",
"New Password": "Nytt lösenord",
"No results found": "",
"No results found": "Inga resultat hittades",
"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",
"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 factually correct": "Inte faktiskt korrekt",
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Merk: Hvis du angir en minimumspoengsum, returnerer søket bare dokumenter med en poengsum som er større enn eller lik minimumspoengsummen.",
"Notifications": "Notifikationer",
"November": "",
"October": "",
"November": "november",
"October": "oktober",
"Off": "Av",
"Okay, Let's Go!": "Okej, nu kör vi!",
"OLED Dark": "",
"Ollama": "",
"Ollama Base URL": "Ollama bas-URL",
"OLED Dark": "OLED mörkt",
"Ollama": "Ollama",
"Ollama API": "",
"Ollama Version": "Ollama-version",
"On": "På",
"Only": "Endast",
......@@ -314,59 +306,54 @@
"Open AI": "Öppna AI",
"Open AI (Dall-E)": "Öppna AI (Dall-E)",
"Open new chat": "Öppna ny chatt",
"OpenAI": "",
"OpenAI": "OpenAI",
"OpenAI API": "OpenAI API",
"OpenAI API Config": "",
"OpenAI API Config": "OpenAI API-konfig",
"OpenAI API Key is required.": "OpenAI API-nyckel krävs.",
"OpenAI URL/Key required.": "",
"OpenAI URL/Key required.": "OpenAI-URL/nyckel krävs.",
"or": "eller",
"Other": "",
"Overview": "",
"Parameters": "Parametrar",
"Other": "Andra",
"Password": "Lösenord",
"PDF document (.pdf)": "",
"PDF document (.pdf)": "PDF-dokument (.pdf)",
"PDF Extract Images (OCR)": "PDF Extrahera bilder (OCR)",
"pending": "väntande",
"Permission denied when accessing microphone: {{error}}": "Tillstånd nekades vid åtkomst till mikrofon: {{error}}",
"Personalization": "",
"Plain text (.txt)": "",
"Personalization": "Personalisering",
"Plain text (.txt)": "Rå text (.txt)",
"Playground": "Lekplats",
"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": "Positivt humör",
"Previous 30 days": "Föregående 30 dagar",
"Previous 7 days": "Föregående 7 dagar",
"Profile Image": "Profilbild",
"Prompt": "Prompt",
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Prompt (t.ex. Berätta mig en rolig faktor om Romerska Imperiet)",
"Prompt Content": "Promptinnehåll",
"Prompt suggestions": "Förslag",
"Prompts": "Prompts",
"Pull \"{{searchValue}}\" from Ollama.com": "",
"Pull \"{{searchValue}}\" from Ollama.com": "Dra \"{{searchValue}}\" från Ollama.com",
"Pull a model from Ollama.com": "Dra en modell från Ollama.com",
"Pull Progress": "Dra framsteg",
"Query Params": "Frågeparametrar",
"RAG Template": "RAG-mall",
"Raw Format": "Råformat",
"Read Aloud": "",
"Read Aloud": "Läs igenom",
"Record voice": "Spela in röst",
"Redirecting you to OpenWebUI Community": "Omdirigerar dig till OpenWebUI Community",
"Refused when it shouldn't have": "",
"Regenerate": "",
"Refused when it shouldn't have": "Avvisades när det inte borde ha",
"Regenerate": "Regenerera",
"Release Notes": "Versionsinformation",
"Remove": "",
"Remove Model": "",
"Rename": "",
"Remove": "Ta bort",
"Remove Model": "Ta bort modell",
"Rename": "Byt namn",
"Repeat Last N": "Upprepa senaste N",
"Repeat Penalty": "Upprepa straff",
"Request Mode": "Begär läge",
"Reranking Model": "",
"Reranking model disabled": "",
"Reranking model set to \"{{reranking_model}}\"": "",
"Reranking Model": "Reranking modell",
"Reranking model disabled": "Reranking modell inaktiverad",
"Reranking model set to \"{{reranking_model}}\"": "Reranking modell inställd på \"{{reranking_model}}\"",
"Reset Vector Storage": "Återställ vektorlager",
"Response AutoCopy to Clipboard": "Svara AutoCopy till urklipp",
"Role": "Roll",
"Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn",
"RTL": "",
"RTL": "RTL",
"Save": "Spara",
"Save & Create": "Spara och skapa",
"Save & Update": "Spara och uppdatera",
......@@ -375,45 +362,48 @@
"Scan complete!": "Skanning klar!",
"Scan for documents from {{path}}": "Skanna efter dokument från {{path}}",
"Search": "Sök",
"Search a model": "",
"Search a model": "Sök efter en modell",
"Search Chats": "",
"Search Documents": "Sök dokument",
"Search Models": "",
"Search Prompts": "Sök promptar",
"See readme.md for instructions": "Se readme.md för instruktioner",
"See what's new": "Se vad som är nytt",
"Seed": "Seed",
"Select a base model": "",
"Select a mode": "Välj ett läge",
"Select a model": "Välj en modell",
"Select an Ollama instance": "Välj en Ollama-instans",
"Select model": "Välj en modell",
"Send": "",
"Selected model(s) do not support image inputs": "",
"Send": "Skicka",
"Send a Message": "Skicka ett meddelande",
"Send message": "Skicka meddelande",
"September": "",
"September": "september",
"Server connection verified": "Serveranslutning verifierad",
"Set as default": "Ange som standard",
"Set Default Model": "Ange standardmodell",
"Set embedding model (e.g. {{model}})": "",
"Set embedding model (e.g. {{model}})": "Ställ in embedding modell (t.ex. {{model}})",
"Set Image Size": "Ange bildstorlek",
"Set Model": "Ställ in modell",
"Set reranking model (e.g. {{model}})": "",
"Set reranking model (e.g. {{model}})": "Ställ in reranking modell (t.ex. {{model}})",
"Set Steps": "Ange steg",
"Set Title Auto-Generation Model": "Ange modell för automatisk generering av titel",
"Set Voice": "Ange röst",
"Settings": "Inställningar",
"Settings saved successfully!": "Inställningar sparades framgångsrikt!",
"Share": "",
"Share Chat": "",
"Share": "Dela",
"Share Chat": "Dela chatt",
"Share to OpenWebUI Community": "Dela till OpenWebUI Community",
"short-summary": "kort sammanfattning",
"Show": "Visa",
"Show Additional Params": "Visa ytterligare parametrar",
"Show shortcuts": "Visa genvägar",
"Showcased creativity": "",
"Showcased creativity": "Visuell kreativitet",
"sidebar": "sidofält",
"Sign in": "Logga in",
"Sign Out": "Logga ut",
"Sign up": "Registrera dig",
"Signing in": "",
"Signing in": "Loggar in",
"Source": "Källa",
"Speech recognition error: {{error}}": "Fel vid taligenkänning: {{error}}",
"Speech-to-Text Engine": "Tal-till-text-motor",
......@@ -421,47 +411,47 @@
"Stop Sequence": "Stoppsekvens",
"STT Settings": "STT-inställningar",
"Submit": "Skicka in",
"Subtitle (e.g. about the Roman Empire)": "",
"Subtitle (e.g. about the Roman Empire)": "Undertext (t.ex. om Romerska Imperiet)",
"Success": "Framgång",
"Successfully updated.": "Uppdaterades framgångsrikt.",
"Suggested": "",
"Sync All": "Synkronisera allt",
"Suggested": "Föreslagen",
"System": "System",
"System Prompt": "Systemprompt",
"Tags": "Taggar",
"Tell us more:": "",
"Tell us more:": "Berätta mer:",
"Temperature": "Temperatur",
"Template": "Mall",
"Text Completion": "Textslutförande",
"Text-to-Speech Engine": "Text-till-tal-motor",
"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!": "Tack för din feedback!",
"The score should be a value between 0.0 (0%) and 1.0 (100%).": "Poäng ska vara ett värde mellan 0,0 (0%) och 1,0 (100%).",
"Theme": "Tema",
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Detta säkerställer att dina värdefulla konversationer sparas säkert till din backend-databas. Tack!",
"This setting does not sync across browsers or devices.": "Denna inställning synkroniseras inte mellan webbläsare eller enheter.",
"Thorough explanation": "",
"Thorough explanation": "Djupare förklaring",
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "Tips: Uppdatera flera variabelplatser efter varandra genom att trycka på tabb-tangenten i chattinmatningen efter varje ersättning.",
"Title": "Titel",
"Title (e.g. Tell me a fun fact)": "",
"Title (e.g. Tell me a fun fact)": "Tittel (f.eks. Fortell meg en fun fact)",
"Title Auto-Generation": "Automatisk generering av titel",
"Title cannot be an empty string.": "",
"Title cannot be an empty string.": "Tittel kan ikke være en tom streng.",
"Title Generation Prompt": "Titelgenereringsprompt",
"to": "till",
"To access the available model names for downloading,": "För att komma åt de tillgängliga modellnamnen för nedladdning,",
"To access the GGUF models available for downloading,": "För att komma åt de GGUF-modeller som finns tillgängliga för nedladdning,",
"to chat input.": "till chattinmatning.",
"Today": "",
"Today": "Idag",
"Toggle settings": "Växla inställningar",
"Toggle sidebar": "Växla sidofält",
"Top K": "Topp K",
"Top P": "Topp P",
"Trouble accessing Ollama?": "Problem med att komma åt Ollama?",
"TTS Settings": "TTS-inställningar",
"Type": "",
"Type Hugging Face Resolve (Download) URL": "Skriv Hugging Face Resolve (nedladdning) URL",
"Uh-oh! There was an issue connecting to {{provider}}.": "Oj då! Det uppstod ett problem med att ansluta till {{provider}}.",
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Okänd filtyp '{{file_type}}', men accepterar och behandlar som vanlig text",
"Update and Copy Link": "",
"Update and Copy Link": "Uppdatera och kopiera länk",
"Update password": "Uppdatera lösenord",
"Upload a GGUF model": "Ladda upp en GGUF-modell",
"Upload files": "Ladda upp filer",
......@@ -478,26 +468,28 @@
"variable": "variabel",
"variable to have them replaced with clipboard content.": "variabel för att få dem ersatta med urklippsinnehåll.",
"Version": "Version",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "",
"Warning": "",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "Varning: Om du uppdaterar eller ändrar din embedding modell måste du importera alla dokument igen.",
"Web": "Webb",
"Web Loader Settings": "",
"Web Params": "",
"Webhook URL": "",
"Web Loader Settings": "Web Loader-inställningar",
"Web Params": "Web-parametrar",
"Webhook URL": "Webhook-URL",
"WebUI Add-ons": "WebUI-tillägg",
"WebUI Settings": "WebUI-inställningar",
"WebUI will make requests to": "WebUI kommer att skicka förfrågningar till",
"What’s New in": "Vad är nytt i",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "När historiken är avstängd visas inte nya chattar i denna webbläsare i din historik på någon av dina enheter.",
"Whisper (Local)": "Whisper (lokal)",
"Workspace": "",
"Workspace": "arbetsyta",
"Write a prompt suggestion (e.g. Who are you?)": "Skriv ett förslag (t.ex. Vem är du?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Skriv en sammanfattning på 50 ord som sammanfattar [ämne eller nyckelord].",
"Yesterday": "",
"You": "",
"You have no archived conversations.": "",
"You have shared this chat": "",
"Yesterday": "Igenom",
"You": "du",
"You cannot clone a base model": "",
"You have no archived conversations.": "Du har inga arkiverade konversationer.",
"You have shared this chat": "Du har delat denna chatt",
"You're a helpful assistant.": "Du är en hjälpsam assistent.",
"You're now logged in.": "Du är nu inloggad.",
"Youtube": "",
"Youtube Loader Settings": ""
"Youtube": "Youtube",
"Youtube Loader Settings": "Youtube Loader-inställningar"
}
......@@ -3,6 +3,8 @@
"(Beta)": "(Beta)",
"(e.g. `sh webui.sh --api`)": "(örn. `sh webui.sh --api`)",
"(latest)": "(en son)",
"{{ models }}": "",
"{{ owner }}: You cannot delete a base model": "",
"{{modelName}} is thinking...": "{{modelName}} düşünüyor...",
"{{user}}'s Chats": "{{user}} Sohbetleri",
"{{webUIName}} Backend Required": "{{webUIName}} Arkayüz Gerekli",
......@@ -10,16 +12,15 @@
"About": "Hakkında",
"Account": "Hesap",
"Accurate information": "Doğru bilgi",
"Add": "",
"Add a model": "Bir model ekleyin",
"Add a model tag name": "Bir model etiket adı ekleyin",
"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": "Ekle",
"Add a model id": "",
"Add a short description about what this model does": "",
"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": "Özel prompt ekle",
"Add Docs": "Dökümanlar Ekle",
"Add Files": "Dosyalar Ekle",
"Add Memory": "",
"Add Memory": "Yerelleştirme Ekle",
"Add message": "Mesaj ekle",
"Add Model": "Model Ekle",
"Add Tags": "Etiketler ekle",
......@@ -29,6 +30,7 @@
"Admin Panel": "Yönetici Paneli",
"Admin Settings": "Yönetici Ayarları",
"Advanced Parameters": "Gelişmiş Parametreler",
"Advanced Params": "",
"all": "tümü",
"All Documents": "Tüm Belgeler",
"All Users": "Tüm Kullanıcılar",
......@@ -43,9 +45,9 @@
"API Key": "API Anahtarı",
"API Key created.": "API Anahtarı oluşturuldu.",
"API keys": "API anahtarları",
"API RPM": "API RPM",
"April": "Nisan",
"Archive": "Arşiv",
"Archive All Chats": "",
"Archived Chats": "Arşivlenmiş Sohbetler",
"are allowed - Activate this command by typing": "izin verilir - Bu komutu yazarak etkinleştirin",
"Are you sure?": "Emin misiniz?",
......@@ -60,16 +62,17 @@
"available!": "mevcut!",
"Back": "Geri",
"Bad Response": "Kötü Yanıt",
"Banners": "",
"Base Model (From)": "",
"before": "önce",
"Being lazy": "Tembelleşiyor",
"Builder Mode": "Oluşturucu Modu",
"Bypass SSL verification for Websites": "Web Siteleri için SSL doğrulamasını atlayın",
"Cancel": "İptal",
"Categories": "Kategoriler",
"Capabilities": "",
"Change Password": "Parola Değiştir",
"Chat": "Sohbet",
"Chat Bubble UI": "",
"Chat direction": "",
"Chat Bubble UI": "Sohbet Balonu UI",
"Chat direction": "Sohbet Yönü",
"Chat History": "Sohbet Geçmişi",
"Chat History is off for this browser.": "Bu tarayıcı için sohbet geçmişi kapalı.",
"Chats": "Sohbetler",
......@@ -83,7 +86,6 @@
"Citation": "Alıntı",
"Click here for help.": "Yardım için buraya tıklayın.",
"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.",
"Click here to select documents.": "Belgeleri seçmek için buraya tıklayın.",
......@@ -108,7 +110,7 @@
"Copy Link": "Bağlantıyı Kopyala",
"Copying to clipboard was successful!": "Panoya kopyalama başarılı!",
"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 a model": "",
"Create Account": "Hesap Oluştur",
"Create new key": "Yeni anahtar oluştur",
"Create new secret key": "Yeni gizli anahtar oluştur",
......@@ -117,9 +119,8 @@
"Current Model": "Mevcut Model",
"Current Password": "Mevcut Parola",
"Custom": "Özel",
"Customize Ollama models for a specific purpose": "Ollama modellerini belirli bir amaç için özelleştirin",
"Customize models for a specific purpose": "",
"Dark": "Koyu",
"Dashboard": "Panel",
"Database": "Veritabanı",
"December": "Aralık",
"Default": "Varsayılan",
......@@ -132,17 +133,17 @@
"delete": "sil",
"Delete": "Sil",
"Delete a model": "Bir modeli sil",
"Delete All Chats": "",
"Delete chat": "Sohbeti sil",
"Delete Chat": "Sohbeti Sil",
"Delete Chats": "Sohbetleri Sil",
"delete this link": "bu bağlantıyı sil",
"Delete User": "Kullanıcıyı Sil",
"Deleted {{deleteModelTag}}": "{{deleteModelTag}} silindi",
"Deleted {{tagName}}": "{{tagName}} silindi",
"Deleted {{name}}": "",
"Description": "Açıklama",
"Didn't fully follow instructions": "Talimatları tam olarak takip etmedi",
"Disabled": "Devre Dışı",
"Discover a modelfile": "Bir model dosyası keşfedin",
"Discover a model": "",
"Discover a prompt": "Bir prompt keşfedin",
"Discover, download, and explore custom prompts": "Özel promptları keşfedin, indirin ve inceleyin",
"Discover, download, and explore model presets": "Model ön ayarlarını keşfedin, indirin ve inceleyin",
......@@ -171,16 +172,11 @@
"Enabled": "Etkin",
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "CSV dosyanızın şu sırayla 4 sütun içerdiğinden emin olun: İsim, E-posta, Şifre, Rol.",
"Enter {{role}} message here": "Buraya {{role}} mesajını girin",
"Enter a detail about yourself for your LLMs to recall": "",
"Enter a detail about yourself for your LLMs to recall": "LLM'lerin hatırlaması için kendiniz hakkında bir detay girin",
"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": "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)",
"Enter LiteLLM Model (litellm_params.model)": "LiteLLM Modelini Girin (litellm_params.model)",
"Enter Max Tokens (litellm_params.max_tokens)": "Maksimum Token Sayısını Girin (litellm_params.max_tokens)",
"Enter model tag (e.g. {{modelTag}})": "Model etiketini girin (örn. {{modelTag}})",
"Enter Number of Steps (e.g. 50)": "Adım Sayısını Girin (örn. 50)",
"Enter Score": "Skoru Girin",
......@@ -192,11 +188,12 @@
"Enter Your Full Name": "Tam Adınızı Girin",
"Enter Your Password": "Parolanızı Girin",
"Enter Your Role": "Rolünüzü Girin",
"Error": "",
"Experimental": "Deneysel",
"Export All Chats (All Users)": "Tüm Sohbetleri Dışa Aktar (Tüm Kullanıcılar)",
"Export Chats": "Sohbetleri Dışa Aktar",
"Export Documents Mapping": "Belge Eşlemesini Dışa Aktar",
"Export Modelfiles": "Model Dosyalarını Dışa Aktar",
"Export Models": "",
"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ı",
......@@ -209,18 +206,17 @@
"Focus chat input": "Sohbet girişine odaklan",
"Followed instructions perfectly": "Talimatları mükemmel şekilde takip etti",
"Format your variables using square brackets like this:": "Değişkenlerinizi şu şekilde kare parantezlerle biçimlendirin:",
"From (Base Model)": "(Temel Model)'den",
"Frequencey Penalty": "",
"Full Screen Mode": "Tam Ekran Modu",
"General": "Genel",
"General Settings": "Genel Ayarlar",
"Generation Info": "Üretim Bilgisi",
"Good Response": "İyi Yanıt",
"h:mm a": "",
"h:mm a": "h:mm a",
"has no conversations.": "hiç konuşması yok.",
"Hello, {{name}}": "Merhaba, {{name}}",
"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?",
"Hybrid Search": "Karma Arama",
"Image Generation (Experimental)": "Görüntü Oluşturma (Deneysel)",
......@@ -229,15 +225,17 @@
"Images": "Görüntüler",
"Import Chats": "Sohbetleri İçe Aktar",
"Import Documents Mapping": "Belge Eşlemesini İçe Aktar",
"Import Modelfiles": "Model Dosyalarını İçe Aktar",
"Import Models": "",
"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",
"Info": "",
"Input commands": "Giriş komutları",
"Interface": "Arayüz",
"Invalid Tag": "Geçersiz etiket",
"January": "Ocak",
"join our Discord for help.": "yardım için Discord'umuza katılın.",
"JSON": "JSON",
"JSON Preview": "",
"July": "Temmuz",
"June": "Haziran",
"JWT Expiration": "JWT Bitişi",
......@@ -249,19 +247,18 @@
"Light": "Açık",
"Listening...": "Dinleniyor...",
"LLMs can make mistakes. Verify important information.": "LLM'ler hata yapabilir. Önemli bilgileri doğrulayın.",
"LTR": "",
"LTR": "LTR",
"Made by OpenWebUI Community": "OpenWebUI Topluluğu tarafından yapılmıştır",
"Make sure to enclose them with": "Değişkenlerinizi şu şekilde biçimlendirin:",
"Manage LiteLLM Models": "LiteLLM Modellerini Yönet",
"Manage Models": "Modelleri Yönet",
"Manage Ollama Models": "Ollama Modellerini Yönet",
"March": "Mart",
"Max Tokens": "Maksimum Token",
"Max Tokens (num_predict)": "",
"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": "Mayıs",
"Memories accessible by LLMs will be shown here.": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "",
"Memories accessible by LLMs will be shown here.": "LLM'ler tarafından erişilebilecek hatalar burada gösterilecektir.",
"Memory": "Hatalar",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Bağlantınızı oluşturduktan sonra gönderdiğiniz mesajlar paylaşılmaz. URL'ye sahip kullanıcılar paylaşılan sohbeti görüntüleyebilir.",
"Minimum Score": "Minimum Skor",
"Mirostat": "Mirostat",
"Mirostat Eta": "Mirostat Eta",
......@@ -271,29 +268,24 @@
"Model '{{modelName}}' has been successfully downloaded.": "'{{modelName}}' başarıyla indirildi.",
"Model '{{modelTag}}' is already in queue for downloading.": "'{{modelTag}}' zaten indirme sırasında.",
"Model {{modelId}} not found": "{{modelId}} bulunamadı",
"Model {{modelName}} already exists.": "{{modelName}} zaten mevcut.",
"Model {{modelName}} is not vision capable": "",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Model dosya sistemi yolu algılandı. Güncelleme için model kısa adı gerekli, devam edilemiyor.",
"Model Name": "Model Adı",
"Model ID": "",
"Model not selected": "Model seçilmedi",
"Model Tag Name": "Model Etiket Adı",
"Model Params": "",
"Model Whitelisting": "Model Beyaz Listeye Alma",
"Model(s) Whitelisted": "Model(ler) Beyaz Listeye Alındı",
"Modelfile": "Model Dosyası",
"Modelfile Advanced Settings": "Model Dosyası Gelişmiş Ayarları",
"Modelfile Content": "Model Dosyası İçeriği",
"Modelfiles": "Model Dosyaları",
"Models": "Modeller",
"More": "Daha Fazla",
"Name": "Ad",
"Name Tag": "Ad Etiketi",
"Name your modelfile": "Model dosyanıza ad verin",
"Name your model": "",
"New Chat": "Yeni Sohbet",
"New Password": "Yeni Parola",
"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": "Kasım",
......@@ -302,7 +294,7 @@
"Okay, Let's Go!": "Tamam, Hadi Başlayalım!",
"OLED Dark": "OLED Koyu",
"Ollama": "Ollama",
"Ollama Base URL": "Ollama Temel URL",
"Ollama API": "",
"Ollama Version": "Ollama Sürümü",
"On": "Açık",
"Only": "Yalnızca",
......@@ -321,14 +313,12 @@
"OpenAI URL/Key required.": "OpenAI URL/Anahtar gereklidir.",
"or": "veya",
"Other": "Diğer",
"Overview": "Genel Bakış",
"Parameters": "Parametreler",
"Password": "Parola",
"PDF document (.pdf)": "PDF belgesi (.pdf)",
"PDF Extract Images (OCR)": "PDF Görüntülerini Çıkart (OCR)",
"pending": "beklemede",
"Permission denied when accessing microphone: {{error}}": "Mikrofona erişim izni reddedildi: {{error}}",
"Personalization": "",
"Personalization": "Kullanıcı Özelleştirme",
"Plain text (.txt)": "Düz metin (.txt)",
"Playground": "Oyun Alanı",
"Positive attitude": "Olumlu yaklaşım",
......@@ -342,10 +332,8 @@
"Prompts": "Promptlar",
"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",
"RAG Template": "RAG Şablonu",
"Raw Format": "Ham Format",
"Read Aloud": "Sesli Oku",
"Record voice": "Ses kaydı yap",
"Redirecting you to OpenWebUI Community": "OpenWebUI Topluluğuna yönlendiriliyorsunuz",
......@@ -356,7 +344,6 @@
"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": "Yeniden Sıralama Modeli",
"Reranking model disabled": "Yeniden sıralama modeli devre dışı bırakıldı",
......@@ -366,7 +353,7 @@
"Role": "Rol",
"Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn",
"RTL": "",
"RTL": "RTL",
"Save": "Kaydet",
"Save & Create": "Kaydet ve Oluştur",
"Save & Update": "Kaydet ve Güncelle",
......@@ -376,16 +363,20 @@
"Scan for documents from {{path}}": "{{path}} dizininden belgeleri tarayın",
"Search": "Ara",
"Search a model": "Bir model ara",
"Search Chats": "",
"Search Documents": "Belgeleri Ara",
"Search Models": "",
"Search Prompts": "Prompt Ara",
"See readme.md for instructions": "Yönergeler için readme.md dosyasına bakın",
"See what's new": "Yeniliklere göz atın",
"Seed": "Seed",
"Select a base model": "",
"Select a mode": "Bir mod seç",
"Select a model": "Bir model seç",
"Select an Ollama instance": "Bir Ollama örneği seçin",
"Select model": "Model seç",
"Send": "",
"Selected model(s) do not support image inputs": "",
"Send": "Gönder",
"Send a Message": "Bir Mesaj Gönder",
"Send message": "Mesaj gönder",
"September": "Eylül",
......@@ -406,7 +397,6 @@
"Share to OpenWebUI Community": "OpenWebUI Topluluğu ile Paylaş",
"short-summary": "kısa-özet",
"Show": "Göster",
"Show Additional Params": "Ek Parametreleri Göster",
"Show shortcuts": "Kısayolları göster",
"Showcased creativity": "Sergilenen yaratıcılık",
"sidebar": "kenar çubuğu",
......@@ -425,7 +415,6 @@
"Success": "Başarılı",
"Successfully updated.": "Başarıyla güncellendi.",
"Suggested": "Önerilen",
"Sync All": "Tümünü Senkronize Et",
"System": "Sistem",
"System Prompt": "Sistem Promptu",
"Tags": "Etiketler",
......@@ -458,6 +447,7 @@
"Top P": "Top P",
"Trouble accessing Ollama?": "Ollama'ya erişmede sorun mu yaşıyorsunuz?",
"TTS Settings": "TTS Ayarları",
"Type": "",
"Type Hugging Face Resolve (Download) URL": "Hugging Face Resolve (Download) URL'sini Yazın",
"Uh-oh! There was an issue connecting to {{provider}}.": "Ah! {{provider}}'a bağlanırken bir sorun oluştu.",
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Bilinmeyen Dosya Türü '{{file_type}}', ancak düz metin olarak kabul ediliyor ve işleniyor",
......@@ -478,6 +468,7 @@
"variable": "değişken",
"variable to have them replaced with clipboard content.": "panodaki içerikle değiştirilmesi için değişken.",
"Version": "Sürüm",
"Warning": "",
"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 Yükleyici Ayarları",
......@@ -489,11 +480,12 @@
"What’s New in": "Yenilikler:",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Geçmiş kapatıldığında, bu tarayıcıdaki yeni sohbetler hiçbir cihazınızdaki geçmişinizde görünmez.",
"Whisper (Local)": "Whisper (Yerel)",
"Workspace": "",
"Workspace": "Çalışma Alanı",
"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": "Dün",
"You": "",
"You": "Sen",
"You cannot clone a base model": "",
"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.",
......
......@@ -3,6 +3,8 @@
"(Beta)": "(Beta)",
"(e.g. `sh webui.sh --api`)": "(e.g. `sh webui.sh --api`)",
"(latest)": "(остання)",
"{{ models }}": "",
"{{ owner }}: You cannot delete a base model": "",
"{{modelName}} is thinking...": "{{modelName}} думає...",
"{{user}}'s Chats": "Чати {{user}}а",
"{{webUIName}} Backend Required": "Необхідно підключення бекенду {{webUIName}}",
......@@ -10,16 +12,15 @@
"About": "Про програму",
"Account": "Обліковий запис",
"Accurate information": "Точна інформація",
"Add": "",
"Add a model": "Додати модель",
"Add a model tag name": "Додати ім'я тегу моделі",
"Add a short description about what this modelfile does": "Додати короткий опис того, що робить цей файл моделі",
"Add": "Додати",
"Add a model id": "",
"Add a short description about what this model does": "",
"Add a short title for this prompt": "Додати коротку назву для цього промту",
"Add a tag": "Додайте тег",
"Add custom prompt": "Додати користувацьку підказку",
"Add Docs": "Додати документи",
"Add Files": "Додати файли",
"Add Memory": "",
"Add Memory": "Додати пам'ять",
"Add message": "Додати повідомлення",
"Add Model": "Додати модель",
"Add Tags": "додати теги",
......@@ -29,6 +30,7 @@
"Admin Panel": "Панель адміністратора",
"Admin Settings": "Налаштування адміністратора",
"Advanced Parameters": "Розширені параметри",
"Advanced Params": "",
"all": "всі",
"All Documents": "Усі документи",
"All Users": "Всі користувачі",
......@@ -43,9 +45,9 @@
"API Key": "Ключ API",
"API Key created.": "Ключ API створено.",
"API keys": "Ключі API",
"API RPM": "API RPM",
"April": "Квітень",
"Archive": "Архів",
"Archive All Chats": "",
"Archived Chats": "Архівовані чати",
"are allowed - Activate this command by typing": "дозволено - активізуйте цю команду набором",
"Are you sure?": "Ви впевнені?",
......@@ -60,16 +62,17 @@
"available!": "доступно!",
"Back": "Назад",
"Bad Response": "Неправильна відповідь",
"Banners": "",
"Base Model (From)": "",
"before": "до того, як",
"Being lazy": "Не поспішати",
"Builder Mode": "Режим конструктора",
"Bypass SSL verification for Websites": "Обхід SSL-перевірки для веб-сайтів",
"Cancel": "Скасувати",
"Categories": "Категорії",
"Capabilities": "",
"Change Password": "Змінити пароль",
"Chat": "Чат",
"Chat Bubble UI": "",
"Chat direction": "",
"Chat Bubble UI": "Бульбашковий UI чату",
"Chat direction": "Напрям чату",
"Chat History": "Історія чату",
"Chat History is off for this browser.": "Історія чату вимкнена для цього браузера.",
"Chats": "Чати",
......@@ -83,7 +86,6 @@
"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.": "Натисніть тут, щоб вибрати документи.",
......@@ -108,7 +110,7 @@
"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':": "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':",
"Create a modelfile": "Створити файл моделі",
"Create a model": "",
"Create Account": "Створити обліковий запис",
"Create new key": "Створити новий ключ",
"Create new secret key": "Створити новий секретний ключ",
......@@ -117,9 +119,8 @@
"Current Model": "Поточна модель",
"Current Password": "Поточний пароль",
"Custom": "Налаштувати",
"Customize Ollama models for a specific purpose": "Налаштувати моделі Ollama для конкретної мети",
"Customize models for a specific purpose": "",
"Dark": "Темна",
"Dashboard": "Панель управління",
"Database": "База даних",
"December": "Грудень",
"Default": "За замовчуванням",
......@@ -132,17 +133,17 @@
"delete": "видалити",
"Delete": "Видалити",
"Delete a model": "Видалити модель",
"Delete All Chats": "",
"Delete chat": "Видалити чат",
"Delete Chat": "Видалити чат",
"Delete Chats": "Видалити чати",
"delete this link": "видалити це посилання",
"Delete User": "Видалити користувача",
"Deleted {{deleteModelTag}}": "Видалено {{deleteModelTag}}",
"Deleted {{tagName}}": "Видалено {{tagName}}",
"Deleted {{name}}": "",
"Description": "Опис",
"Didn't fully follow instructions": "Не повністю дотримувалися інструкцій",
"Disabled": "Вимкнено",
"Discover a modelfile": "Знайти файл моделі",
"Discover a model": "",
"Discover a prompt": "Знайти промт",
"Discover, download, and explore custom prompts": "Знайдіть, завантажте та досліджуйте налаштовані промти",
"Discover, download, and explore model presets": "Знайдіть, завантажте та досліджуйте налаштовані налаштування моделі",
......@@ -171,16 +172,11 @@
"Enabled": "Увімкнено",
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Переконайтеся, що ваш CSV-файл містить 4 колонки в такому порядку: Ім'я, Email, Пароль, Роль.",
"Enter {{role}} message here": "Введіть повідомлення {{role}} тут",
"Enter a detail about yourself for your LLMs to recall": "",
"Enter a detail about yourself for your LLMs to recall": "Введіть відомості про себе для запам'ятовування вашими LLM.",
"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": "Введіть бал",
......@@ -192,11 +188,12 @@
"Enter Your Full Name": "Введіть ваше ім'я",
"Enter Your Password": "Введіть ваш пароль",
"Enter Your Role": "Введіть вашу роль",
"Error": "",
"Experimental": "Експериментальне",
"Export All Chats (All Users)": "Експортувати всі чати (всі користувачі)",
"Export Chats": "Експортувати чати",
"Export Documents Mapping": "Експортувати відображення документів",
"Export Modelfiles": "Експортувати файл моделі",
"Export Models": "",
"Export Prompts": "Експортувати промти",
"Failed to create API Key.": "Не вдалося створити API ключ.",
"Failed to read clipboard contents": "Не вдалося прочитати вміст буфера обміну",
......@@ -209,18 +206,17 @@
"Focus chat input": "Фокус вводу чату",
"Followed instructions perfectly": "Бездоганно дотримувався інструкцій",
"Format your variables using square brackets like this:": "Форматуйте свої змінні квадратними дужками так:",
"From (Base Model)": "Від (базова модель)",
"Frequencey Penalty": "",
"Full Screen Mode": "Режим повного екрану",
"General": "Загальні",
"General Settings": "Загальні налаштування",
"Generation Info": "Інформація про генерацію",
"Good Response": "Гарна відповідь",
"h:mm a": "",
"h:mm a": "h:mm a",
"has no conversations.": "не має розмов.",
"Hello, {{name}}": "Привіт, {{name}}",
"Help": "Допоможіть",
"Hide": "Приховати",
"Hide Additional Params": "Приховати додаткові параметри",
"How can I help you today?": "Чим я можу допомогти вам сьогодні?",
"Hybrid Search": "Гібридний пошук",
"Image Generation (Experimental)": "Генерування зображень (експериментально)",
......@@ -229,15 +225,17 @@
"Images": "Зображення",
"Import Chats": "Імпортувати чати",
"Import Documents Mapping": "Імпортувати відображення документів",
"Import Modelfiles": "Імпортувати файл моделі",
"Import Models": "",
"Import Prompts": "Імпортувати промти",
"Include `--api` flag when running stable-diffusion-webui": "Включіть прапор `--api` при запуску stable-diffusion-webui",
"Info": "",
"Input commands": "Команди вводу",
"Interface": "Інтерфейс",
"Invalid Tag": "Недійсний тег",
"January": "Січень",
"join our Discord for help.": "приєднуйтеся до нашого Discord для допомоги.",
"JSON": "JSON",
"JSON Preview": "",
"July": "Липень",
"June": "Червень",
"JWT Expiration": "Термін дії JWT",
......@@ -249,19 +247,18 @@
"Light": "Світла",
"Listening...": "Слухаю...",
"LLMs can make mistakes. Verify important information.": "LLMs можуть помилятися. Перевірте важливу інформацію.",
"LTR": "",
"LTR": "LTR",
"Made by OpenWebUI Community": "Зроблено спільнотою OpenWebUI",
"Make sure to enclose them with": "Переконайтеся, що вони закриті",
"Manage LiteLLM Models": "Керування моделями LiteLLM",
"Manage Models": "Керування моделями",
"Manage Ollama Models": "Керування моделями Ollama",
"March": "Березень",
"Max Tokens": "Максимальна кількість токенів",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимум 3 моделі можна завантажити одночасно. Будь ласка, спробуйте пізніше.",
"May": "Травень",
"Memories accessible by LLMs will be shown here.": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "",
"Memories accessible by LLMs will be shown here.": "Пам'ять, яка доступна LLM, буде показана тут.",
"Memory": "Пам'ять",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Повідомлення, які ви надішлете після створення посилання, не будуть доступні для інших. Користувачі, які мають URL, зможуть переглядати спільний чат.",
"Minimum Score": "Мінімальний бал",
"Mirostat": "Mirostat",
"Mirostat Eta": "Mirostat Eta",
......@@ -271,29 +268,24 @@
"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}} is not vision capable": "",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Виявлено шлях до файлової системи моделі. Для оновлення потрібно вказати коротке ім'я моделі, не вдасться продовжити.",
"Model Name": "Назва моделі",
"Model ID": "",
"Model not selected": "Модель не вибрана",
"Model Tag Name": "Ім'я тегу моделі",
"Model Params": "",
"Model Whitelisting": "Модель білого списку",
"Model(s) Whitelisted": "Модель(і) білого списку",
"Modelfile": "Файли моделі",
"Modelfile Advanced Settings": "Додаткові налаштування файлу моделі",
"Modelfile Content": "Вміст файлу моделі",
"Modelfiles": "Файли моделей",
"Models": "Моделі",
"More": "Більше",
"Name": "Ім'я",
"Name Tag": "Назва тегу",
"Name your modelfile": "Назвіть свій файл моделі",
"Name your model": "",
"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": "Листопад",
......@@ -302,7 +294,7 @@
"Okay, Let's Go!": "Гаразд, давайте почнемо!",
"OLED Dark": "Темний OLED",
"Ollama": "Ollama",
"Ollama Base URL": "URL-адреса Ollama",
"Ollama API": "",
"Ollama Version": "Версія Ollama",
"On": "Увімк",
"Only": "Тільки",
......@@ -321,14 +313,12 @@
"OpenAI URL/Key required.": "Потрібен OpenAI URL/ключ.",
"or": "або",
"Other": "Інше",
"Overview": "Огляд",
"Parameters": "Параметри",
"Password": "Пароль",
"PDF document (.pdf)": "PDF документ (.pdf)",
"PDF Extract Images (OCR)": "Розпізнавання зображень з PDF (OCR)",
"pending": "на розгляді",
"Permission denied when accessing microphone: {{error}}": "Доступ до мікрофона заборонено: {{error}}",
"Personalization": "",
"Personalization": "Персоналізація",
"Plain text (.txt)": "Простий текст (.txt)",
"Playground": "Майданчик",
"Positive attitude": "Позитивне ставлення",
......@@ -342,10 +332,8 @@
"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",
......@@ -356,7 +344,6 @@
"Remove Model": "Видалити модель",
"Rename": "Перейменувати",
"Repeat Last N": "Повторити останні N",
"Repeat Penalty": "Штраф за повторення",
"Request Mode": "Режим запиту",
"Reranking Model": "Модель переранжування",
"Reranking model disabled": "Модель переранжування вимкнена",
......@@ -366,7 +353,7 @@
"Role": "Роль",
"Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn",
"RTL": "",
"RTL": "RTL",
"Save": "Зберегти",
"Save & Create": "Зберегти та створити",
"Save & Update": "Зберегти та оновити",
......@@ -376,16 +363,20 @@
"Scan for documents from {{path}}": "Сканування документів з {{path}}",
"Search": "Пошук",
"Search a model": "Шукати модель",
"Search Chats": "",
"Search Documents": "Пошук документів",
"Search Models": "",
"Search Prompts": "Пошук промтів",
"See readme.md for instructions": "Див. readme.md для інструкцій",
"See what's new": "Подивіться, що нового",
"Seed": "Сід",
"Select a base model": "",
"Select a mode": "Оберіть режим",
"Select a model": "Виберіть модель",
"Select an Ollama instance": "Виберіть екземпляр Ollama",
"Select model": "Вибрати модель",
"Send": "",
"Selected model(s) do not support image inputs": "",
"Send": "Надіслати",
"Send a Message": "Надіслати повідомлення",
"Send message": "Надіслати повідомлення",
"September": "Вересень",
......@@ -406,7 +397,6 @@
"Share to OpenWebUI Community": "Поділитися зі спільнотою OpenWebUI",
"short-summary": "короткий зміст",
"Show": "Показати",
"Show Additional Params": "Показати додаткові параметри",
"Show shortcuts": "Показати клавіатурні скорочення",
"Showcased creativity": "Продемонстрований креатив",
"sidebar": "бокова панель",
......@@ -425,7 +415,6 @@
"Success": "Успіх",
"Successfully updated.": "Успішно оновлено.",
"Suggested": "Запропоновано",
"Sync All": "Синхронізувати все",
"System": "Система",
"System Prompt": "Системний промт",
"Tags": "Теги",
......@@ -458,6 +447,7 @@
"Top P": "Top P",
"Trouble accessing Ollama?": "Проблеми з доступом до Ollama?",
"TTS Settings": "Налаштування TTS",
"Type": "",
"Type Hugging Face Resolve (Download) URL": "Введіть URL ресурсу Hugging Face Resolve (завантаження)",
"Uh-oh! There was an issue connecting to {{provider}}.": "Ой! Виникла проблема при підключенні до {{provider}}.",
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Невідомий тип файлу '{{file_type}}', але приймається та обробляється як звичайний текст",
......@@ -478,6 +468,7 @@
"variable": "змінна",
"variable to have them replaced with clipboard content.": "змінна, щоб замінити їх вмістом буфера обміну.",
"Version": "Версія",
"Warning": "",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "Попередження: Якщо ви оновлюєте або змінюєте модель вбудовування, вам потрібно буде повторно імпортувати всі документи.",
"Web": "Веб",
"Web Loader Settings": "Налаштування веб-завантажувача",
......@@ -489,11 +480,12 @@
"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)": "Whisper (локально)",
"Workspace": "",
"Workspace": "Робочий простір",
"Write a prompt suggestion (e.g. Who are you?)": "Напишіть промт (напр., Хто ти?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Напишіть стислий зміст у 50 слів, який узагальнює [тема або ключове слово].",
"Yesterday": "Вчора",
"You": "",
"You": "Ви",
"You cannot clone a base model": "",
"You have no archived conversations.": "У вас немає архівованих розмов.",
"You have shared this chat": "Ви поділилися цим чатом",
"You're a helpful assistant.": "Ви корисний асистент.",
......
......@@ -3,23 +3,24 @@
"(Beta)": "(Beta)",
"(e.g. `sh webui.sh --api`)": "(vd: `sh webui.sh --api`)",
"(latest)": "(mới nhất)",
"{{ models }}": "",
"{{ owner }}: You cannot delete a base model": "{{ owner }}: Bạn không thể xóa base model",
"{{modelName}} is thinking...": "{{modelName}} đang suy nghĩ...",
"{{user}}'s Chats": "",
"{{user}}'s Chats": "{{user}}'s Chats",
"{{webUIName}} Backend Required": "{{webUIName}} Yêu cầu Backend",
"a user": "người sử dụng",
"About": "Giới thiệu",
"Account": "Tài khoản",
"Accurate information": "Thông tin chính xác",
"Add": "",
"Add a model": "Thêm mô hình",
"Add a model tag name": "Thêm tên thẻ mô hình (tag)",
"Add a short description about what this modelfile does": "Thêm mô tả ngắn về việc tệp mô tả mô hình (modelfile) này làm gì",
"Add": "Thêm",
"Add a model id": "",
"Add a short description about what this model does": "Thêm mô tả ngắn về những khả năng của model",
"Add a short title for this prompt": "Thêm tiêu đề ngắn cho prompt này",
"Add a tag": "Thêm thẻ (tag)",
"Add custom prompt": "Thêm prompt tùy chỉnh",
"Add Docs": "Thêm tài liệu",
"Add Files": "Thêm tệp",
"Add Memory": "",
"Add Memory": "Thêm bộ nhớ",
"Add message": "Thêm tin nhắn",
"Add Model": "Thêm model",
"Add Tags": "thêm thẻ",
......@@ -29,6 +30,7 @@
"Admin Panel": "Trang Quản trị",
"Admin Settings": "Cài đặt hệ thống",
"Advanced Parameters": "Các tham số Nâng cao",
"Advanced Params": "",
"all": "tất cả",
"All Documents": "Tất cả tài liệu",
"All Users": "Danh sách người sử dụng",
......@@ -41,11 +43,11 @@
"and create a new shared link.": "và tạo một link chia sẻ mới",
"API Base URL": "Đường dẫn tới API (API Base URL)",
"API Key": "API Key",
"API Key created.": "",
"API keys": "",
"API RPM": "API RPM",
"API Key created.": "Khóa API đã tạo",
"API keys": "API Keys",
"April": "Tháng 4",
"Archive": "Lưu trữ",
"Archive All Chats": "Lưu tất cả các cuộc Chat",
"Archived Chats": "bản ghi trò chuyện",
"are allowed - Activate this command by typing": "được phép - Kích hoạt lệnh này bằng cách gõ",
"Are you sure?": "Bạn có chắc chắn không?",
......@@ -60,16 +62,17 @@
"available!": "có sẵn!",
"Back": "Quay lại",
"Bad Response": "Trả lời KHÔNG tốt",
"Banners": "",
"Base Model (From)": "",
"before": "trước",
"Being lazy": "Lười biếng",
"Builder Mode": "Chế độ Builder",
"Bypass SSL verification for Websites": "",
"Bypass SSL verification for Websites": "Bỏ qua xác thực SSL cho các trang web",
"Cancel": "Hủy bỏ",
"Categories": "Danh mục",
"Capabilities": "Năng lực",
"Change Password": "Đổi Mật khẩu",
"Chat": "Trò chuyện",
"Chat Bubble UI": "",
"Chat direction": "",
"Chat Bubble UI": "Bảng chat",
"Chat direction": "Hướng chat",
"Chat History": "Lịch sử chat",
"Chat History is off for this browser.": "Lịch sử chat đã tắt cho trình duyệt này.",
"Chats": "Chat",
......@@ -83,7 +86,6 @@
"Citation": "Trích dẫn",
"Click here for help.": "Bấm vào đây để được trợ giúp.",
"Click here to": "Nhấn vào đây để",
"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.",
"Click here to select": "Bấm vào đây để chọn",
"Click here to select a csv file.": "Nhấn vào đây để chọn tệp csv",
"Click here to select documents.": "Bấm vào đây để chọn tài liệu.",
......@@ -91,9 +93,9 @@
"Click on the user role button to change a user's role.": "Bấm vào nút trong cột VAI TRÒ để thay đổi quyền của người sử dụng.",
"Close": "Đóng",
"Collection": "Tổng hợp mọi tài liệu",
"ComfyUI": "",
"ComfyUI Base URL": "",
"ComfyUI Base URL is required.": "",
"ComfyUI": "ComfyUI",
"ComfyUI Base URL": "ComfyUI Base URL",
"ComfyUI Base URL is required.": "Base URL của ComfyUI là bắt buộc.",
"Command": "Lệnh",
"Confirm Password": "Xác nhận Mật khẩu",
"Connections": "Kết nối",
......@@ -101,14 +103,14 @@
"Context Length": "Độ dài ngữ cảnh (Context Length)",
"Continue Response": "Tiếp tục trả lời",
"Conversation Mode": "Chế độ hội thoại",
"Copied shared chat URL to clipboard!": "",
"Copied shared chat URL to clipboard!": "Đã sao chép link chia sẻ trò chuyện vào clipboard!",
"Copy": "Sao chép",
"Copy last code block": "Sao chép khối mã cuối cùng",
"Copy last response": "Sao chép phản hồi cuối cùng",
"Copy Link": "Sao chép link",
"Copying to clipboard was successful!": "Sao chép vào clipboard thành công!",
"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':": "Tạo một cụm từ súc tích, 3-5 từ làm tiêu đề cho truy vấn sau, tuân thủ nghiêm ngặt giới hạn 3-5 từ và tránh sử dụng từ 'tiêu đề':",
"Create a modelfile": "Tạo tệp mô tả cho mô hình",
"Create a model": "Tạo model",
"Create Account": "Tạo Tài khoản",
"Create new key": "Tạo key mới",
"Create new secret key": "Tạo key bí mật mới",
......@@ -117,14 +119,13 @@
"Current Model": "Mô hình hiện tại",
"Current Password": "Mật khẩu hiện tại",
"Custom": "Tùy chỉnh",
"Customize Ollama models for a specific purpose": "Tùy chỉnh các mô hình dựa trên Ollama cho một mục đích cụ thể",
"Customize models for a specific purpose": "Tùy chỉnh model cho những mục đích riêng",
"Dark": "Tối",
"Dashboard": "",
"Database": "Cơ sở dữ liệu",
"December": "Tháng 12",
"Default": "Mặc định",
"Default (Automatic1111)": "Mặc định (Automatic1111)",
"Default (SentenceTransformers)": "",
"Default (SentenceTransformers)": "Mặc định (SentenceTransformers)",
"Default (Web API)": "Mặc định (Web API)",
"Default model updated": "Mô hình mặc định đã được cập nhật",
"Default Prompt Suggestions": "Đề xuất prompt mặc định",
......@@ -132,17 +133,17 @@
"delete": "xóa",
"Delete": "Xóa",
"Delete a model": "Xóa mô hình",
"Delete All Chats": "Xóa mọi cuộc Chat",
"Delete chat": "Xóa nội dung chat",
"Delete Chat": "Xóa chat",
"Delete Chats": "Xóa nội dung chat",
"delete this link": "Xóa link này",
"Delete User": "Xóa người dùng",
"Deleted {{deleteModelTag}}": "Đã xóa {{deleteModelTag}}",
"Deleted {{tagName}}": "Xóa {{tagName}}",
"Deleted {{name}}": "Đã xóa {{name}}",
"Description": "Mô tả",
"Didn't fully follow instructions": "Không tuân theo chỉ dẫn một cách đầy đủ",
"Disabled": "Đã vô hiệu hóa",
"Discover a modelfile": "Khám phá thêm các mô hình mới",
"Discover a model": "Khám phá model",
"Discover a prompt": "Khám phá thêm prompt mới",
"Discover, download, and explore custom prompts": "Tìm kiếm, tải về và khám phá thêm các prompt tùy chỉnh",
"Discover, download, and explore model presets": "Tìm kiếm, tải về và khám phá thêm các thiết lập mô hình sẵn",
......@@ -163,40 +164,36 @@
"Edit Doc": "Thay đổi tài liệu",
"Edit User": "Thay đổi thông tin người sử dụng",
"Email": "Email",
"Embedding Model": "",
"Embedding Model Engine": "",
"Embedding model set to \"{{embedding_model}}\"": "",
"Embedding Model": "Mô hình embedding",
"Embedding Model Engine": "Trình xử lý embedding",
"Embedding model set to \"{{embedding_model}}\"": "Mô hình embedding đã được thiết lập thành \"{{embedding_model}}\"",
"Enable Chat History": "Bật Lịch sử chat",
"Enable New Sign Ups": "Cho phép đăng ký mới",
"Enabled": "Đã bật",
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Đảm bảo tệp CSV của bạn bao gồm 4 cột theo thứ tự sau: Name, Email, Password, Role.",
"Enter {{role}} message here": "Nhập yêu cầu của {{role}} ở đây",
"Enter a detail about yourself for your LLMs to recall": "",
"Enter a detail about yourself for your LLMs to recall": "Nhập chi tiết về bản thân của bạn để LLMs có thể nhớ",
"Enter Chunk Overlap": "Nhập Chunk chồng lấn (overlap)",
"Enter Chunk Size": "Nhập Kích thước Chunk",
"Enter Image Size (e.g. 512x512)": "Nhập Kích thước ảnh (vd: 512x512)",
"Enter language codes": "",
"Enter LiteLLM API Base URL (litellm_params.api_base)": "Nhập URL Cơ bản API LiteLLM (litellm_params.api_base)",
"Enter LiteLLM API Key (litellm_params.api_key)": "Nhập Khóa API LiteLLM (litellm_params.api_key)",
"Enter LiteLLM API RPM (litellm_params.rpm)": "Nhập RPM API LiteLLM (litellm_params.rpm)",
"Enter LiteLLM Model (litellm_params.model)": "Nhập Mô hình LiteLLM (litellm_params.model)",
"Enter Max Tokens (litellm_params.max_tokens)": "Nhập Số Token Tối đa (litellm_params.max_tokens)",
"Enter language codes": "Nhập mã ngôn ngữ",
"Enter model tag (e.g. {{modelTag}})": "Nhập thẻ mô hình (vd: {{modelTag}})",
"Enter Number of Steps (e.g. 50)": "Nhập số Steps (vd: 50)",
"Enter Score": "Nhập Score",
"Enter stop sequence": "Nhập stop sequence",
"Enter Top K": "Nhập Top K",
"Enter URL (e.g. http://127.0.0.1:7860/)": "Nhập URL (vd: http://127.0.0.1:7860/)",
"Enter URL (e.g. http://localhost:11434)": "",
"Enter URL (e.g. http://localhost:11434)": "Nhập URL (vd: http://localhost:11434)",
"Enter Your Email": "Nhập Email của bạn",
"Enter Your Full Name": "Nhập Họ và Tên của bạn",
"Enter Your Password": "Nhập Mật khẩu của bạn",
"Enter Your Role": "Nhập vai trò của bạn",
"Error": "Lỗi",
"Experimental": "Thử nghiệm",
"Export All Chats (All Users)": "Tải về tất cả nội dung chat (tất cả mọi người)",
"Export Chats": "Tải nội dung chat về máy",
"Export Documents Mapping": "Tải cấu trúc tài liệu về máy",
"Export Modelfiles": "Tải tệp mô tả về máy",
"Export Models": "",
"Export Prompts": "Tải các prompt về máy",
"Failed to create API Key.": "Lỗi khởi tạo API Key",
"Failed to read clipboard contents": "Không thể đọc nội dung clipboard",
......@@ -204,40 +201,41 @@
"Feel free to add specific details": "Mô tả chi tiết về chất lượng của câu hỏi và phương án trả lời",
"File Mode": "Chế độ Tệp văn bản",
"File not found.": "Không tìm thấy tệp.",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Phát hiện giả mạo vân tay: Không thể sử dụng tên viết tắt làm hình đại diện. Mặc định là hình ảnh hồ sơ mặc định.",
"Fluidly stream large external response chunks": "Truyền tải các khối phản hồi bên ngoài lớn một cách trôi chảy",
"Focus chat input": "Tập trung vào nội dung chat",
"Followed instructions perfectly": "Tuân theo chỉ dẫn một cách hoàn hảo",
"Format your variables using square brackets like this:": "Định dạng các biến của bạn bằng cách sử dụng dấu ngoặc vuông như thế này:",
"From (Base Model)": "Từ (Base Model)",
"Frequencey Penalty": "",
"Full Screen Mode": "Chế độ Toàn màn hình",
"General": "Cài đặt chung",
"General Settings": "Cấu hình chung",
"Generation Info": "Thông tin chung",
"Good Response": "Trả lời tốt",
"h:mm a": "",
"h:mm a": "h:mm a",
"has no conversations.": "không có hội thoại",
"Hello, {{name}}": "Xin chào, {{name}}",
"Hello, {{name}}": "Xin chào {{name}}",
"Help": "Trợ giúp",
"Hide": "Ẩn",
"Hide Additional Params": "Ẩn Các tham số bổ sung",
"How can I help you today?": "Tôi có thể giúp gì cho bạn hôm nay?",
"Hybrid Search": "",
"Hybrid Search": "Tìm kiếm Hybrid",
"Image Generation (Experimental)": "Tạo ảnh (thử nghiệm)",
"Image Generation Engine": "Công cụ tạo ảnh",
"Image Settings": "Cài đặt ảnh",
"Images": "Hình ảnh",
"Import Chats": "Nạp lại nội dung chat",
"Import Documents Mapping": "Nạp cấu trúc tài liệu",
"Import Modelfiles": "Nạp tệp mô tả",
"Import Models": "Nạp model",
"Import Prompts": "Nạp các prompt lên hệ thống",
"Include `--api` flag when running stable-diffusion-webui": "Bao gồm flag `--api` khi chạy stable-diffusion-webui",
"Info": "Thông tin",
"Input commands": "Nhập các câu lệnh",
"Interface": "Giao diện",
"Invalid Tag": "Tag không hợp lệ",
"January": "Tháng 1",
"join our Discord for help.": "tham gia Discord của chúng tôi để được trợ giúp.",
"JSON": "JSON",
"JSON Preview": "",
"July": "Tháng 7",
"June": "Tháng 6",
"JWT Expiration": "JWT Hết hạn",
......@@ -249,60 +247,54 @@
"Light": "Sáng",
"Listening...": "Đang nghe...",
"LLMs can make mistakes. Verify important information.": "Hệ thống có thể tạo ra nội dung không chính xác hoặc sai. Hãy kiểm chứng kỹ lưỡng thông tin trước khi tiếp nhận và sử dụng.",
"LTR": "",
"LTR": "LTR",
"Made by OpenWebUI Community": "Được tạo bởi Cộng đồng OpenWebUI",
"Make sure to enclose them with": "Hãy chắc chắn bao quanh chúng bằng",
"Manage LiteLLM Models": "Quản lý mô hình với LiteLLM",
"Manage Models": "Quản lý mô hình",
"Manage Ollama Models": "Quản lý mô hình với Ollama",
"March": "Tháng 3",
"Max Tokens": "Max Tokens",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Tối đa 3 mô hình có thể được tải xuống cùng lúc. Vui lòng thử lại sau.",
"May": "Tháng 5",
"Memories accessible by LLMs will be shown here.": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "",
"Memories accessible by LLMs will be shown here.": "Memory có thể truy cập bởi LLMs sẽ hiển thị ở đây.",
"Memory": "Memory",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Tin nhắn bạn gửi sau khi tạo liên kết sẽ không được chia sẻ. Người dùng có URL sẽ có thể xem cuộc trò chuyện được chia sẻ.",
"Minimum Score": "Score tối thiểu",
"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.": "Mô hình '{{modelName}}' đã được tải xuống thành công.",
"Model '{{modelTag}}' is already in queue for downloading.": "Mô hình '{{modelTag}}' đã có trong hàng đợi để tải xuống.",
"Model {{modelId}} not found": "Không tìm thấy Mô hình {{modelId}}",
"Model {{modelName}} already exists.": "Mô hình {{modelName}} đã tồn tại.",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "",
"Model Name": "Tên Mô hình",
"Model {{modelName}} is not vision capable": "",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Đường dẫn hệ thống tệp mô hình được phát hiện. Tên viết tắt mô hình là bắt buộc để cập nhật, không thể tiếp tục.",
"Model ID": "",
"Model not selected": "Chưa chọn Mô hình",
"Model Tag Name": "Tên thẻ Mô hình",
"Model Params": "",
"Model Whitelisting": "Whitelist mô hình",
"Model(s) Whitelisted": "các mô hình được cho vào danh sách Whitelist",
"Modelfile": "Tệp Mô hình",
"Modelfile Advanced Settings": "Cài đặt Nâng cao Tệp Mô hình",
"Modelfile Content": "Nội dung Tệp Mô hình",
"Modelfiles": "Tệp Mô hình",
"Models": "Mô hình",
"More": "Thêm",
"Name": "Tên",
"Name Tag": "Tên Thẻ",
"Name your modelfile": "Đặt tên cho tệp mô hình của bạn",
"New Chat": "Tạo cuộc trò chuyện mới",
"Name your model": "Tên model",
"New Chat": "Tạo chat mới",
"New Password": "Mật khẩu mới",
"No results found": "Không tìm thấy kết quả",
"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",
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Lưu ý: Nếu bạn đặt điểm (Score) tối thiểu thì tìm kiếm sẽ chỉ trả về những tài liệu có điểm lớn hơn hoặc bằng điểm tối thiểu.",
"Notifications": "Thông báo trên máy tính (Notification)",
"November": "Tháng 11",
"October": "Tháng 10",
"Off": "Tắt",
"Okay, Let's Go!": "Được rồi, Bắt đầu thôi!",
"OLED Dark": "",
"Ollama": "",
"Ollama Base URL": "Đường dẫn tới API của Ollama (Ollama Base URL)",
"OLED Dark": "OLED Dark",
"Ollama": "Ollama",
"Ollama API": "",
"Ollama Version": "Phiên bản Ollama",
"On": "Bật",
"Only": "Only",
......@@ -314,38 +306,34 @@
"Open AI": "Open AI",
"Open AI (Dall-E)": "Open AI (Dall-E)",
"Open new chat": "Mở nội dung chat mới",
"OpenAI": "",
"OpenAI": "OpenAI",
"OpenAI API": "API OpenAI",
"OpenAI API Config": "",
"OpenAI API Config": "Cấu hình API OpenAI",
"OpenAI API Key is required.": "Bắt buộc nhập API OpenAI Key.",
"OpenAI URL/Key required.": "",
"OpenAI URL/Key required.": "Yêu cầu URL/Key API OpenAI.",
"or": "hoặc",
"Other": "Khác",
"Overview": "Tổng quan",
"Parameters": "Tham số",
"Password": "Mật khẩu",
"PDF document (.pdf)": "",
"PDF document (.pdf)": "Tập tin PDF (.pdf)",
"PDF Extract Images (OCR)": "Trích xuất ảnh từ PDF (OCR)",
"pending": "đang chờ phê duyệt",
"Permission denied when accessing microphone: {{error}}": "Quyền truy cập micrô bị từ chối: {{error}}",
"Personalization": "Cá nhân hóa",
"Plain text (.txt)": "",
"Plain text (.txt)": "Văn bản thô (.txt)",
"Playground": "Thử nghiệm (Playground)",
"Positive attitude": "Thái độ tích cực",
"Previous 30 days": "30 ngày trước",
"Previous 7 days": "7 ngày trước",
"Profile Image": "Ảnh đại diện",
"Prompt": "",
"Prompt": "Prompt",
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Prompt (ví dụ: Hãy kể cho tôi một sự thật thú vị về Đế chế La Mã)",
"Prompt Content": "Nội dung prompt",
"Prompt suggestions": "Gợi ý prompt",
"Prompts": "Prompt",
"Pull \"{{searchValue}}\" from Ollama.com": "",
"Pull \"{{searchValue}}\" from Ollama.com": "Tải \"{{searchValue}}\" từ Ollama.com",
"Pull a model from Ollama.com": "Tải mô hình từ Ollama.com",
"Pull Progress": "Tiến trình Tải xuống",
"Query Params": "Tham số Truy vấn",
"RAG Template": "Mẫu prompt cho RAG",
"Raw Format": "Raw Format",
"Read Aloud": "Đọc ra loa",
"Record voice": "Ghi âm",
"Redirecting you to OpenWebUI Community": "Đang chuyển hướng bạn đến Cộng đồng OpenWebUI",
......@@ -356,17 +344,16 @@
"Remove Model": "Xóa model",
"Rename": "Đổi tên",
"Repeat Last N": "Repeat Last N",
"Repeat Penalty": "Repeat Penalty",
"Request Mode": "Request Mode",
"Reranking Model": "",
"Reranking model disabled": "",
"Reranking model set to \"{{reranking_model}}\"": "",
"Reranking Model": "Reranking Model",
"Reranking model disabled": "Reranking model disabled",
"Reranking model set to \"{{reranking_model}}\"": "Reranking model set to \"{{reranking_model}}\"",
"Reset Vector Storage": "Cài đặt lại Vector Storage",
"Response AutoCopy to Clipboard": "Tự động Sao chép Phản hồi vào clipboard",
"Role": "Vai trò",
"Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn",
"RTL": "",
"RTL": "RTL",
"Save": "Lưu",
"Save & Create": "Lưu & Tạo",
"Save & Update": "Lưu & Cập nhật",
......@@ -376,15 +363,19 @@
"Scan for documents from {{path}}": "Quét tài liệu từ đường dẫn: {{path}}",
"Search": "Tìm kiếm",
"Search a model": "Tìm model",
"Search Chats": "Tìm kiếm các cuộc Chat",
"Search Documents": "Tìm tài liệu",
"Search Models": "Tìm model",
"Search Prompts": "Tìm prompt",
"See readme.md for instructions": "Xem readme.md để biết hướng dẫn",
"See what's new": "Xem những cập nhật mới",
"Seed": "Seed",
"Select a base model": "Chọn một base model",
"Select a mode": "Chọn một chế độ",
"Select a model": "Chọn mô hình",
"Select an Ollama instance": "Chọn một thực thể Ollama",
"Select model": "Chọn model",
"Selected model(s) do not support image inputs": "",
"Send": "Gửi",
"Send a Message": "Gửi yêu cầu",
"Send message": "Gửi yêu cầu",
......@@ -392,10 +383,10 @@
"Server connection verified": "Kết nối máy chủ đã được xác minh",
"Set as default": "Đặt làm mặc định",
"Set Default Model": "Đặt Mô hình Mặc định",
"Set embedding model (e.g. {{model}})": "",
"Set embedding model (e.g. {{model}})": "Thiết lập mô hình embedding (ví dụ: {{model}})",
"Set Image Size": "Đặt Kích thước ảnh",
"Set Model": "Thiết lập mô hình",
"Set reranking model (e.g. {{model}})": "",
"Set reranking model (e.g. {{model}})": "Thiết lập mô hình reranking (ví dụ: {{model}})",
"Set Steps": "Đặt Số Bước",
"Set Title Auto-Generation Model": "Đặt tiêu đề tự động",
"Set Voice": "Đặt Giọng nói",
......@@ -406,14 +397,13 @@
"Share to OpenWebUI Community": "Chia sẻ đến Cộng đồng OpenWebUI",
"short-summary": "tóm tắt ngắn",
"Show": "Hiển thị",
"Show Additional Params": "Hiển thị Tham số Bổ sung",
"Show shortcuts": "Hiển thị phím tắt",
"Showcased creativity": "Thể hiện sự sáng tạo",
"sidebar": "thanh bên",
"Sign in": "Đăng nhập",
"Sign Out": "Đăng xuất",
"Sign up": "Đăng ký",
"Signing in": "",
"Signing in": "Đăng nhập",
"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",
......@@ -421,16 +411,15 @@
"Stop Sequence": "Trình tự Dừng",
"STT Settings": "Cài đặt Nhận dạng Giọng nói",
"Submit": "Gửi",
"Subtitle (e.g. about the Roman Empire)": "",
"Subtitle (e.g. about the Roman Empire)": "Phụ đề (ví dụ: về Đế chế La Mã)",
"Success": "Thành công",
"Successfully updated.": "Đã cập nhật thành công.",
"Suggested": "Gợi ý một số mẫu prompt",
"Sync All": "Đồng bộ hóa Tất cả",
"System": "Hệ thống",
"System Prompt": "Prompt Hệ thống (System Prompt)",
"Tags": "Thẻ",
"Tell us more:": "Hãy cho chúng tôi hiểu thêm về chất lượng của câu trả lời:",
"Temperature": "Temperature",
"Temperature": "Mức độ sáng tạo",
"Template": "Mẫu",
"Text Completion": "Hoàn tất Văn bản",
"Text-to-Speech Engine": "Công cụ Chuyển Văn bản thành Giọng nói",
......@@ -458,6 +447,7 @@
"Top P": "Top P",
"Trouble accessing Ollama?": "Gặp vấn đề khi truy cập Ollama?",
"TTS Settings": "Cài đặt Chuyển văn bản thành Giọng nói",
"Type": "Kiểu",
"Type Hugging Face Resolve (Download) URL": "Nhập URL Hugging Face Resolve (Tải xuống)",
"Uh-oh! There was an issue connecting to {{provider}}.": "Ồ! Đã xảy ra sự cố khi kết nối với {{provider}}.",
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Loại Tệp Không xác định '{{file_type}}', nhưng đang chấp nhận và xử lý như văn bản thô",
......@@ -478,26 +468,28 @@
"variable": "biến",
"variable to have them replaced with clipboard content.": "biến để có chúng được thay thế bằng nội dung clipboard.",
"Version": "Version",
"Warning": "Cảnh báo",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "Cảnh báo: Nếu cập nhật hoặc thay đổi embedding model, bạn sẽ cần cập nhật lại tất cả tài liệu.",
"Web": "Web",
"Web Loader Settings": "Cài đặt Web Loader",
"Web Params": "",
"Webhook URL": "",
"Web Params": "Web Params",
"Webhook URL": "Webhook URL",
"WebUI Add-ons": "Tiện ích WebUI",
"WebUI Settings": "Cài đặt WebUI",
"WebUI will make requests to": "WebUI sẽ thực hiện các yêu cầu đến",
"What’s New in": "",
"What’s New in": "Thông tin mới về",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Khi chế độ lịch sử chat đã tắt, các nội dung chat mới trên trình duyệt này sẽ không xuất hiện trên bất kỳ thiết bị nào của bạn.",
"Whisper (Local)": "Whisper (Local)",
"Workspace": "",
"Workspace": "Workspace",
"Write a prompt suggestion (e.g. Who are you?)": "Hãy viết một prompt (vd: Bạn là ai?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Viết một tóm tắt trong vòng 50 từ cho [chủ đề hoặc từ khóa].",
"Yesterday": "Hôm qua",
"You": "Bạn",
"You cannot clone a base model": "Bạn không thể nhân bản base model",
"You have no archived conversations.": "Bạn chưa lưu trữ một nội dung chat nào",
"You have shared this chat": "Bạn vừa chia sẻ chat này",
"You're a helpful assistant.": "Bạn là một trợ lý hữu ích.",
"You're now logged in.": "Bạn đã đăng nhập.",
"Youtube": "",
"Youtube": "Youtube",
"Youtube Loader Settings": "Cài đặt Youtube Loader"
}
......@@ -3,6 +3,8 @@
"(Beta)": "(测试版)",
"(e.g. `sh webui.sh --api`)": "(例如 `sh webui.sh --api`)",
"(latest)": "(最新版)",
"{{ models }}": "",
"{{ owner }}: You cannot delete a base model": "",
"{{modelName}} is thinking...": "{{modelName}} 正在思考...",
"{{user}}'s Chats": "{{user}} 的聊天记录",
"{{webUIName}} Backend Required": "需要 {{webUIName}} 后端",
......@@ -10,16 +12,15 @@
"About": "关于",
"Account": "账户",
"Accurate information": "准确信息",
"Add": "",
"Add a model": "添加模型",
"Add a model tag name": "添加模型标签名称",
"Add a short description about what this modelfile does": "为这个模型文件添加一段简短的描述",
"Add": "添加",
"Add a model id": "",
"Add a short description about what this model does": "",
"Add a short title for this prompt": "为这个提示词添加一个简短的标题",
"Add a tag": "添加标签",
"Add custom prompt": "添加自定义提示词",
"Add Docs": "添加文档",
"Add Files": "添加文件",
"Add Memory": "",
"Add Memory": "添加记忆",
"Add message": "添加消息",
"Add Model": "添加模型",
"Add Tags": "添加标签",
......@@ -29,6 +30,7 @@
"Admin Panel": "管理员面板",
"Admin Settings": "管理员设置",
"Advanced Parameters": "高级参数",
"Advanced Params": "",
"all": "所有",
"All Documents": "所有文档",
"All Users": "所有用户",
......@@ -43,9 +45,9 @@
"API Key": "API 密钥",
"API Key created.": "API 密钥已创建。",
"API keys": "API 密钥",
"API RPM": "API RPM",
"April": "四月",
"Archive": "存档",
"Archive All Chats": "",
"Archived Chats": "聊天记录存档",
"are allowed - Activate this command by typing": "允许 - 通过输入来激活这个命令",
"Are you sure?": "你确定吗?",
......@@ -60,16 +62,17 @@
"available!": "可用!",
"Back": "返回",
"Bad Response": "不良响应",
"Banners": "",
"Base Model (From)": "",
"before": "之前",
"Being lazy": "懒惰",
"Builder Mode": "构建模式",
"Bypass SSL verification for Websites": "绕过网站的 SSL 验证",
"Cancel": "取消",
"Categories": "分类",
"Capabilities": "",
"Change Password": "更改密码",
"Chat": "聊天",
"Chat Bubble UI": "",
"Chat direction": "",
"Chat Bubble UI": "聊天气泡 UI",
"Chat direction": "聊天方向",
"Chat History": "聊天历史",
"Chat History is off for this browser.": "此浏览器已关闭聊天历史功能。",
"Chats": "聊天",
......@@ -83,7 +86,6 @@
"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.": "点击这里选择文档。",
......@@ -108,7 +110,7 @@
"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 a model": "",
"Create Account": "创建账户",
"Create new key": "创建新密钥",
"Create new secret key": "创建新安全密钥",
......@@ -117,9 +119,8 @@
"Current Model": "当前模型",
"Current Password": "当前密码",
"Custom": "自定义",
"Customize Ollama models for a specific purpose": "定制特定用途的 Ollama 模型",
"Customize models for a specific purpose": "",
"Dark": "暗色",
"Dashboard": "仪表盘",
"Database": "数据库",
"December": "十二月",
"Default": "默认",
......@@ -132,17 +133,17 @@
"delete": "删除",
"Delete": "删除",
"Delete a model": "删除一个模型",
"Delete All Chats": "",
"Delete chat": "删除聊天",
"Delete Chat": "删除聊天",
"Delete Chats": "删除聊天记录",
"delete this link": "删除这个链接",
"Delete User": "删除用户",
"Deleted {{deleteModelTag}}": "已删除{{deleteModelTag}}",
"Deleted {{tagName}}": "已删除 {{tagName}}",
"Deleted {{name}}": "",
"Description": "描述",
"Didn't fully follow instructions": "没有完全遵循指示",
"Disabled": "禁用",
"Discover a modelfile": "探索模型文件",
"Discover a model": "",
"Discover a prompt": "探索提示词",
"Discover, download, and explore custom prompts": "发现、下载并探索自定义提示词",
"Discover, download, and explore model presets": "发现、下载并探索模型预设",
......@@ -171,16 +172,11 @@
"Enabled": "启用",
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "确保您的 CSV 文件按以下顺序包含 4 列: 姓名、电子邮件、密码、角色。",
"Enter {{role}} message here": "在此处输入 {{role}} 信息",
"Enter a detail about yourself for your LLMs to recall": "",
"Enter a detail about yourself for your LLMs to recall": "输入 LLM 可以记住的信息",
"Enter Chunk Overlap": "输入块重叠 (Chunk Overlap)",
"Enter Chunk Size": "输入块大小 (Chunk Size)",
"Enter Image Size (e.g. 512x512)": "输入图片大小 (例如 512x512)",
"Enter language codes": "输入语言代码",
"Enter LiteLLM API Base URL (litellm_params.api_base)": "输入 LiteLLM API 基本 URL (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 速率限制 (litellm_params.rpm)",
"Enter LiteLLM Model (litellm_params.model)": "输入 LiteLLM 模型 (litellm_params.model)",
"Enter Max Tokens (litellm_params.max_tokens)": "输入模型的 Max Tokens (litellm_params.max_tokens)",
"Enter model tag (e.g. {{modelTag}})": "输入模型标签 (例如{{modelTag}})",
"Enter Number of Steps (e.g. 50)": "输入步数 (例如 50)",
"Enter Score": "输入分",
......@@ -192,11 +188,12 @@
"Enter Your Full Name": "输入您的全名",
"Enter Your Password": "输入您的密码",
"Enter Your Role": "输入您的角色",
"Error": "",
"Experimental": "实验性",
"Export All Chats (All Users)": "导出所有聊天(所有用户)",
"Export Chats": "导出聊天",
"Export Documents Mapping": "导出文档映射",
"Export Modelfiles": "导出模型文件",
"Export Models": "",
"Export Prompts": "导出提示词",
"Failed to create API Key.": "无法创建 API 密钥。",
"Failed to read clipboard contents": "无法读取剪贴板内容",
......@@ -209,7 +206,7 @@
"Focus chat input": "聚焦聊天输入",
"Followed instructions perfectly": "完全遵循说明",
"Format your variables using square brackets like this:": "使用这样的方括号格式化你的变量:",
"From (Base Model)": "来自(基础模型)",
"Frequencey Penalty": "",
"Full Screen Mode": "全屏模式",
"General": "通用",
"General Settings": "通用设置",
......@@ -220,7 +217,6 @@
"Hello, {{name}}": "你好,{{name}}",
"Help": "帮助",
"Hide": "隐藏",
"Hide Additional Params": "隐藏额外参数",
"How can I help you today?": "我今天能帮你做什么?",
"Hybrid Search": "混合搜索",
"Image Generation (Experimental)": "图像生成(实验性)",
......@@ -229,15 +225,17 @@
"Images": "图像",
"Import Chats": "导入聊天",
"Import Documents Mapping": "导入文档映射",
"Import Modelfiles": "导入模型文件",
"Import Models": "",
"Import Prompts": "导入提示",
"Include `--api` flag when running stable-diffusion-webui": "运行 stable-diffusion-webui 时包含 `--api` 标志",
"Info": "",
"Input commands": "输入命令",
"Interface": "界面",
"Invalid Tag": "无效标签",
"January": "一月",
"join our Discord for help.": "加入我们的 Discord 寻求帮助。",
"JSON": "JSON",
"JSON Preview": "",
"July": "七月",
"June": "六月",
"JWT Expiration": "JWT 过期",
......@@ -249,19 +247,18 @@
"Light": "浅色",
"Listening...": "监听中...",
"LLMs can make mistakes. Verify important information.": "LLM 可能会生成错误信息,请验证重要信息。",
"LTR": "",
"LTR": "LTR",
"Made by OpenWebUI Community": "由 OpenWebUI 社区制作",
"Make sure to enclose them with": "确保将它们包含在内",
"Manage LiteLLM Models": "管理 LiteLLM 模型",
"Manage Models": "管理模型",
"Manage Ollama Models": "管理 Ollama 模型",
"March": "三月",
"Max Tokens": "最大令牌数",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "最多可以同时下载 3 个模型,请稍后重试。",
"May": "五月",
"Memories accessible by LLMs will be shown here.": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "",
"Memories accessible by LLMs will be shown here.": "LLMs 可以访问的记忆将显示在这里。",
"Memory": "记忆",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "创建链接后发送的消息不会被共享。具有 URL 的用户将能够查看共享聊天。",
"Minimum Score": "最低分",
"Mirostat": "Mirostat",
"Mirostat Eta": "Mirostat Eta",
......@@ -271,29 +268,24 @@
"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}} is not vision capable": "",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "检测到模型文件系统路径。模型简名是更新所必需的,无法继续。",
"Model Name": "模型名称",
"Model ID": "",
"Model not selected": "未选择模型",
"Model Tag Name": "模型标签名称",
"Model Params": "",
"Model Whitelisting": "白名单模型",
"Model(s) Whitelisted": "模型已加入白名单",
"Modelfile": "模型文件",
"Modelfile Advanced Settings": "模型文件高级设置",
"Modelfile Content": "模型文件内容",
"Modelfiles": "模型文件",
"Models": "模型",
"More": "更多",
"Name": "名称",
"Name Tag": "名称标签",
"Name your modelfile": "命名你的模型文件",
"Name your model": "",
"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": "十一月",
......@@ -302,7 +294,7 @@
"Okay, Let's Go!": "好的,我们开始吧!",
"OLED Dark": "暗黑色",
"Ollama": "Ollama",
"Ollama Base URL": "Ollama 基础 URL",
"Ollama API": "",
"Ollama Version": "Ollama 版本",
"On": "开",
"Only": "仅",
......@@ -321,15 +313,13 @@
"OpenAI URL/Key required.": "需要 OpenAI URL/Key",
"or": "或",
"Other": "其他",
"Overview": "概述",
"Parameters": "参数",
"Password": "密码",
"PDF document (.pdf)": "PDF 文档 (.pdf)",
"PDF Extract Images (OCR)": "PDF 图像处理 (使用 OCR)",
"pending": "待定",
"Permission denied when accessing microphone: {{error}}": "访问麦克风时权限被拒绝:{{error}}",
"Personalization": "",
"Plain text (.txt)": "PDF 文档 (.pdf)",
"Personalization": "个性化",
"Plain text (.txt)": "TXT 文档 (.txt)",
"Playground": "AI 对话游乐场",
"Positive attitude": "积极态度",
"Previous 30 days": "过去 30 天",
......@@ -342,10 +332,8 @@
"Prompts": "提示词",
"Pull \"{{searchValue}}\" from Ollama.com": "从 Ollama.com 拉取 \"{{searchValue}}\"",
"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 社区",
......@@ -356,7 +344,6 @@
"Remove Model": "移除模型",
"Rename": "重命名",
"Repeat Last N": "重复最后 N 次",
"Repeat Penalty": "重复惩罚",
"Request Mode": "请求模式",
"Reranking Model": "重排模型",
"Reranking model disabled": "重排模型已禁用",
......@@ -366,7 +353,7 @@
"Role": "角色",
"Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn",
"RTL": "",
"RTL": "RTL",
"Save": "保存",
"Save & Create": "保存并创建",
"Save & Update": "保存并更新",
......@@ -376,15 +363,19 @@
"Scan for documents from {{path}}": "从 {{path}} 扫描文档",
"Search": "搜索",
"Search a model": "搜索模型",
"Search Chats": "",
"Search Documents": "搜索文档",
"Search Models": "",
"Search Prompts": "搜索提示词",
"See readme.md for instructions": "查看 readme.md 以获取说明",
"See what's new": "查看最新内容",
"Seed": "种子",
"Select a base model": "",
"Select a mode": "选择一个模式",
"Select a model": "选择一个模型",
"Select an Ollama instance": "选择一个 Ollama 实例",
"Select model": "选择模型",
"Selected model(s) do not support image inputs": "",
"Send": "发送",
"Send a Message": "发送消息",
"Send message": "发送消息",
......@@ -406,7 +397,6 @@
"Share to OpenWebUI Community": "分享到 OpenWebUI 社区",
"short-summary": "简短总结",
"Show": "显示",
"Show Additional Params": "显示额外参数",
"Show shortcuts": "显示快捷方式",
"Showcased creativity": "展示创意",
"sidebar": "侧边栏",
......@@ -425,7 +415,6 @@
"Success": "成功",
"Successfully updated.": "成功更新。",
"Suggested": "建议",
"Sync All": "同步所有",
"System": "系统",
"System Prompt": "系统提示",
"Tags": "标签",
......@@ -458,6 +447,7 @@
"Top P": "Top P",
"Trouble accessing Ollama?": "访问 Ollama 时遇到问题?",
"TTS Settings": "文本转语音设置",
"Type": "",
"Type Hugging Face Resolve (Download) URL": "输入 Hugging Face 解析(下载)URL",
"Uh-oh! There was an issue connecting to {{provider}}.": "哎呀!连接到{{provider}}时出现问题。",
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "未知文件类型'{{file_type}}',将视为纯文本进行处理",
......@@ -478,6 +468,7 @@
"variable": "变量",
"variable to have them replaced with clipboard content.": "变量将被剪贴板内容替换。",
"Version": "版本",
"Warning": "",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "警告: 如果更新或更改 embedding 模型,则需要重新导入所有文档。",
"Web": "网页",
"Web Loader Settings": "Web 加载器设置",
......@@ -493,7 +484,8 @@
"Write a prompt suggestion (e.g. Who are you?)": "写一个提示建议(例如:你是谁?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "用 50 个字写一个总结 [主题或关键词]。",
"Yesterday": "昨天",
"You": "",
"You": "你",
"You cannot clone a base model": "",
"You have no archived conversations.": "你没有存档的对话。",
"You have shared this chat": "你分享了这次聊天",
"You're a helpful assistant.": "你是一个有帮助的助手。",
......
......@@ -3,34 +3,36 @@
"(Beta)": "(測試版)",
"(e.g. `sh webui.sh --api`)": "(例如 `sh webui.sh --api`)",
"(latest)": "(最新版)",
"{{ models }}": "",
"{{ owner }}: You cannot delete a base model": "",
"{{modelName}} is thinking...": "{{modelName}} 正在思考...",
"{{user}}'s Chats": "",
"{{user}}'s Chats": "{{user}} 的聊天",
"{{webUIName}} Backend Required": "需要 {{webUIName}} 後台",
"a user": "使用者",
"About": "關於",
"Account": "帳號",
"Accurate information": "",
"Add": "",
"Add a model": "新增模型",
"Add a model tag name": "新增模型標籤",
"Add a short description about what this modelfile does": "為這個 Modelfile 添加一段簡短的描述",
"Accurate information": "準確信息",
"Add": "新增",
"Add a model id": "",
"Add a short description about what this model does": "",
"Add a short title for this prompt": "為這個提示詞添加一個簡短的標題",
"Add a tag": "新增標籤",
"Add custom prompt": "新增自定義提示詞",
"Add Docs": "新增文件",
"Add Files": "新增檔案",
"Add Memory": "",
"Add Memory": "新增記憶",
"Add message": "新增訊息",
"Add Model": "",
"Add Model": "新增模型",
"Add Tags": "新增標籤",
"Add User": "",
"Add User": "新增用户",
"Adjusting these settings will apply changes universally to all users.": "調整這些設定將對所有使用者進行更改。",
"admin": "管理員",
"Admin Panel": "管理員控制台",
"Admin Settings": "管理設定",
"Advanced Parameters": "進階參數",
"Advanced Params": "",
"all": "所有",
"All Documents": "",
"All Documents": "所有文件",
"All Users": "所有使用者",
"Allow": "允許",
"Allow Chat Deletion": "允許刪除聊天紀錄",
......@@ -38,38 +40,39 @@
"Already have an account?": "已經有帳號了嗎?",
"an assistant": "助手",
"and": "和",
"and create a new shared link.": "",
"and create a new shared link.": "創建一個新的共享連結。",
"API Base URL": "API 基本 URL",
"API Key": "API 金鑰",
"API Key created.": "",
"API keys": "",
"API RPM": "API RPM",
"April": "",
"Archive": "",
"API Key": "API Key",
"API Key created.": "API Key",
"API keys": "API Keys",
"April": "4月",
"Archive": "存檔",
"Archive All Chats": "",
"Archived Chats": "聊天記錄存檔",
"are allowed - Activate this command by typing": "是允許的 - 透過輸入",
"Are you sure?": "你確定嗎?",
"Attach file": "附加檔案",
"Attention to detail": "",
"Attention to detail": "細節精確",
"Audio": "音訊",
"August": "",
"August": "8月",
"Auto-playback response": "自動播放回答",
"Auto-send input after 3 sec.": "3 秒後自動傳送輸入內容",
"AUTOMATIC1111 Base URL": "AUTOMATIC1111 基本 URL",
"AUTOMATIC1111 Base URL is required.": "需要 AUTOMATIC1111 基本 URL",
"available!": "可以使用!",
"Back": "返回",
"Bad Response": "",
"before": "",
"Being lazy": "",
"Builder Mode": "建構模式",
"Bypass SSL verification for Websites": "",
"Bad Response": "錯誤回應",
"Banners": "",
"Base Model (From)": "",
"before": "前",
"Being lazy": "懶人模式",
"Bypass SSL verification for Websites": "跳過 SSL 驗證",
"Cancel": "取消",
"Categories": "分類",
"Capabilities": "",
"Change Password": "修改密碼",
"Chat": "聊天",
"Chat Bubble UI": "",
"Chat direction": "",
"Chat Bubble UI": "聊天氣泡介面",
"Chat direction": "聊天方向",
"Chat History": "聊天紀錄功能",
"Chat History is off for this browser.": "此瀏覽器已關閉聊天紀錄功能。",
"Chats": "聊天",
......@@ -82,67 +85,65 @@
"Chunk Size": "Chunk 大小",
"Citation": "引文",
"Click here for help.": "點擊這裡尋找幫助。",
"Click here to": "",
"Click here to check other modelfiles.": "點擊這裡檢查其他 Modelfiles。",
"Click here to": "點擊這裡",
"Click here to select": "點擊這裡選擇",
"Click here to select a csv file.": "",
"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.": "點擊使用者 Role 按鈕以更改使用者的 Role。",
"Close": "關閉",
"Collection": "收藏",
"ComfyUI": "",
"ComfyUI Base URL": "",
"ComfyUI Base URL is required.": "",
"ComfyUI": "ComfyUI",
"ComfyUI Base URL": "ComfyUI 基本 URL",
"ComfyUI Base URL is required.": "需要 ComfyUI 基本 URL",
"Command": "命令",
"Confirm Password": "確認密碼",
"Connections": "連線",
"Content": "內容",
"Context Length": "上下文長度",
"Continue Response": "",
"Continue Response": "繼續回答",
"Conversation Mode": "對話模式",
"Copied shared chat URL to clipboard!": "",
"Copy": "",
"Copied shared chat URL to clipboard!": "已複製共享聊天連結到剪貼簿!",
"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": "建立 Modelfile",
"Create a model": "",
"Create Account": "建立帳號",
"Create new key": "",
"Create new secret key": "",
"Create new key": "建立新密鑰",
"Create new secret key": "建立新密鑰",
"Created at": "建立於",
"Created At": "",
"Created At": "建立於",
"Current Model": "目前模型",
"Current Password": "目前密碼",
"Custom": "自訂",
"Customize Ollama models for a specific purpose": "定制特定用途的 Ollama 模型",
"Customize models for a specific purpose": "",
"Dark": "暗色",
"Dashboard": "",
"Database": "資料庫",
"December": "",
"December": "12月",
"Default": "預設",
"Default (Automatic1111)": "預設(Automatic1111)",
"Default (SentenceTransformers)": "",
"Default (SentenceTransformers)": "預設(SentenceTransformers)",
"Default (Web API)": "預設(Web API)",
"Default model updated": "預設模型已更新",
"Default Prompt Suggestions": "預設提示詞建議",
"Default User Role": "預設用戶 Role",
"delete": "刪除",
"Delete": "",
"Delete": "刪除",
"Delete a model": "刪除一個模型",
"Delete All Chats": "",
"Delete chat": "刪除聊天紀錄",
"Delete Chat": "",
"Delete Chats": "刪除聊天紀錄",
"delete this link": "",
"Delete User": "",
"Delete Chat": "刪除聊天紀錄",
"delete this link": "刪除此連結",
"Delete User": "刪除用戶",
"Deleted {{deleteModelTag}}": "已刪除 {{deleteModelTag}}",
"Deleted {{tagName}}": "",
"Deleted {{name}}": "",
"Description": "描述",
"Didn't fully follow instructions": "",
"Didn't fully follow instructions": "無法完全遵循指示",
"Disabled": "已停用",
"Discover a modelfile": "發現新 Modelfile",
"Discover a model": "",
"Discover a prompt": "發現新提示詞",
"Discover, download, and explore custom prompts": "發現、下載並探索他人設置的提示詞",
"Discover, download, and explore model presets": "發現、下載並探索他人設置的模型",
......@@ -153,156 +154,147 @@
"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": "電子郵件",
"Embedding Model": "",
"Embedding Model Engine": "",
"Embedding model set to \"{{embedding_model}}\"": "",
"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.": "",
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "請確保你的 CSV 檔案包含這四個欄位,並按照此順序:名稱、電子郵件、密碼、角色。",
"Enter {{role}} message here": "在這裡輸入 {{role}} 訊息",
"Enter a detail about yourself for your LLMs to recall": "",
"Enter a detail about yourself for your LLMs to recall": "輸入 LLM 記憶的詳細內容",
"Enter Chunk Overlap": "輸入 Chunk Overlap",
"Enter Chunk Size": "輸入 Chunk 大小",
"Enter Image Size (e.g. 512x512)": "輸入圖片大小(例如 512x512)",
"Enter language codes": "",
"Enter LiteLLM API Base URL (litellm_params.api_base)": "輸入 LiteLLM API 基本 URL(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(litellm_params.rpm)",
"Enter LiteLLM Model (litellm_params.model)": "輸入 LiteLLM 模型(litellm_params.model)",
"Enter Max Tokens (litellm_params.max_tokens)": "輸入最大 Token 數(litellm_params.max_tokens)",
"Enter language codes": "輸入語言代碼",
"Enter model tag (e.g. {{modelTag}})": "輸入模型標籤(例如 {{modelTag}})",
"Enter Number of Steps (e.g. 50)": "輸入步數(例如 50)",
"Enter Score": "",
"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)": "",
"Enter URL (e.g. http://localhost:11434)": "輸入 URL(例如 http://localhost:11434)",
"Enter Your Email": "輸入你的電子郵件",
"Enter Your Full Name": "輸入你的全名",
"Enter Your Password": "輸入你的密碼",
"Enter Your Role": "",
"Enter Your Role": "輸入你的角色",
"Error": "",
"Experimental": "實驗功能",
"Export All Chats (All Users)": "匯出所有聊天紀錄(所有使用者)",
"Export Chats": "匯出聊天紀錄",
"Export Documents Mapping": "匯出文件映射",
"Export Modelfiles": "匯出 Modelfiles",
"Export Models": "",
"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": "",
"February": "2月",
"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.": "",
"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": "",
"Followed instructions perfectly": "完全遵循指示",
"Format your variables using square brackets like this:": "像這樣使用方括號來格式化你的變數:",
"From (Base Model)": "來自(基礎模型)",
"Frequencey Penalty": "",
"Full Screen Mode": "全螢幕模式",
"General": "常用",
"General Settings": "常用設定",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Generation Info": "生成信息",
"Good Response": "優秀的回應",
"h:mm a": "h:mm a",
"has no conversations.": "沒有對話",
"Hello, {{name}}": "你好,{{name}}",
"Help": "",
"Help": "幫助",
"Hide": "隱藏",
"Hide Additional Params": "隱藏額外參數",
"How can I help you today?": "今天能為你做什麼?",
"Hybrid Search": "",
"Hybrid Search": "混合搜索",
"Image Generation (Experimental)": "圖像生成(實驗功能)",
"Image Generation Engine": "圖像生成引擎",
"Image Settings": "圖片設定",
"Images": "圖片",
"Import Chats": "匯入聊天紀錄",
"Import Documents Mapping": "匯入文件映射",
"Import Modelfiles": "匯入 Modelfiles",
"Import Models": "",
"Import Prompts": "匯入提示詞",
"Include `--api` flag when running stable-diffusion-webui": "在運行 stable-diffusion-webui 時加上 `--api` 標誌",
"Info": "",
"Input commands": "輸入命令",
"Interface": "介面",
"Invalid Tag": "",
"January": "",
"Invalid Tag": "無效標籤",
"January": "1月",
"join our Discord for help.": "加入我們的 Discord 尋找幫助。",
"JSON": "JSON",
"July": "",
"June": "",
"JSON Preview": "",
"July": "7月",
"June": "6月",
"JWT Expiration": "JWT 過期時間",
"JWT Token": "JWT Token",
"Keep Alive": "保持活躍",
"Keyboard shortcuts": "鍵盤快速鍵",
"Language": "語言",
"Last Active": "",
"Last Active": "最後活動",
"Light": "亮色",
"Listening...": "正在聽取...",
"LLMs can make mistakes. Verify important information.": "LLM 可能會產生錯誤。請驗證重要資訊。",
"LTR": "",
"LTR": "LTR",
"Made by OpenWebUI Community": "由 OpenWebUI 社區製作",
"Make sure to enclose them with": "請確保變數有被以下符號框住:",
"Manage LiteLLM Models": "管理 LiteLLM 模型",
"Manage Models": "管理模組",
"Manage Ollama Models": "管理 Ollama 模型",
"March": "",
"Max Tokens": "最大 Token 數",
"March": "3月",
"Max Tokens (num_predict)": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "最多可以同時下載 3 個模型。請稍後再試。",
"May": "",
"Memories accessible by LLMs will be shown here.": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "",
"Minimum Score": "",
"May": "5月",
"Memories accessible by LLMs will be shown here.": "LLM 記憶將會顯示在此處。",
"Memory": "記憶",
"Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "創建連結後發送的訊息將不會被共享。具有 URL 的用戶將會能夠檢視共享的聊天。",
"Minimum Score": "最小分數",
"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.": "'{{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 {{modelName}} is not vision capable": "",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "模型文件系統路徑已檢測。需要更新模型短名,無法繼續。",
"Model ID": "",
"Model not selected": "未選擇模型",
"Model Tag Name": "模型標籤",
"Model Params": "",
"Model Whitelisting": "白名單模型",
"Model(s) Whitelisted": "模型已加入白名單",
"Modelfile": "Modelfile",
"Modelfile Advanced Settings": "Modelfile 進階設定",
"Modelfile Content": "Modelfile 內容",
"Modelfiles": "Modelfiles",
"Models": "模型",
"More": "",
"More": "更多",
"Name": "名稱",
"Name Tag": "名稱標籤",
"Name your modelfile": "命名你的 Modelfile",
"Name your model": "",
"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.": "",
"Not factually correct": "與真實資訊不相符",
"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": "11月",
"October": "10 月",
"Off": "關閉",
"Okay, Let's Go!": "好的,啟動吧!",
"OLED Dark": "",
"Ollama": "",
"Ollama Base URL": "Ollama 基本 URL",
"OLED Dark": "`",
"Ollama": "Ollama",
"Ollama API": "",
"Ollama Version": "Ollama 版本",
"On": "開啟",
"Only": "僅有",
......@@ -314,59 +306,54 @@
"Open AI": "Open AI",
"Open AI (Dall-E)": "Open AI (Dall-E)",
"Open new chat": "開啟新聊天",
"OpenAI": "",
"OpenAI": "OpenAI",
"OpenAI API": "OpenAI API",
"OpenAI API Config": "",
"OpenAI API Config": "OpenAI API 設定",
"OpenAI API Key is required.": "需要 OpenAI API 金鑰。",
"OpenAI URL/Key required.": "",
"OpenAI URL/Key required.": "需要 OpenAI URL/金鑰。",
"or": "或",
"Other": "",
"Overview": "",
"Parameters": "參數",
"Other": "其他",
"Password": "密碼",
"PDF document (.pdf)": "",
"PDF document (.pdf)": "PDF 文件 (.pdf)",
"PDF Extract Images (OCR)": "PDF 圖像擷取(OCR 光學文字辨識)",
"pending": "待審查",
"Permission denied when accessing microphone: {{error}}": "存取麥克風時被拒絕權限:{{error}}",
"Personalization": "",
"Plain text (.txt)": "",
"Personalization": "個人化",
"Plain text (.txt)": "純文字 (.txt)",
"Playground": "AI 對話遊樂場",
"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": "積極態度",
"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": "",
"Pull \"{{searchValue}}\" from Ollama.com": "從 Ollama.com 下載 \"{{searchValue}}\"",
"Pull a model from Ollama.com": "從 Ollama.com 下載模型",
"Pull Progress": "下載進度",
"Query Params": "查詢參數",
"RAG Template": "RAG 範例",
"Raw Format": "原始格式",
"Read Aloud": "",
"Read Aloud": "讀出",
"Record voice": "錄音",
"Redirecting you to OpenWebUI Community": "將你重新導向到 OpenWebUI 社群",
"Refused when it shouldn't have": "",
"Regenerate": "",
"Refused when it shouldn't have": "拒絕時不該拒絕",
"Regenerate": "重新生成",
"Release Notes": "發布說明",
"Remove": "",
"Remove Model": "",
"Rename": "",
"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": "重新排序模型",
"Reranking model disabled": "重新排序模型已禁用",
"Reranking model set to \"{{reranking_model}}\"": "重新排序模型設定為 \"{{reranking_model}}\"",
"Reset Vector Storage": "重置向量儲存空間",
"Response AutoCopy to Clipboard": "自動複製回答到剪貼簿",
"Role": "Role",
"Rosé Pine": "玫瑰松",
"Rosé Pine Dawn": "黎明玫瑰松",
"RTL": "",
"RTL": "RTL",
"Save": "儲存",
"Save & Create": "儲存並建立",
"Save & Update": "儲存並更新",
......@@ -375,27 +362,31 @@
"Scan complete!": "掃描完成!",
"Scan for documents from {{path}}": "從 {{path}} 掃描文件",
"Search": "搜尋",
"Search a model": "",
"Search a model": "搜尋模型",
"Search Chats": "",
"Search Documents": "搜尋文件",
"Search Models": "",
"Search Prompts": "搜尋提示詞",
"See readme.md for instructions": "查看 readme.md 獲取指南",
"See what's new": "查看最新內容",
"Seed": "種子",
"Select a base model": "",
"Select a mode": "選擇模式",
"Select a model": "選擇一個模型",
"Select an Ollama instance": "選擇 Ollama 實例",
"Select model": "選擇模型",
"Send": "",
"Selected model(s) do not support image inputs": "",
"Send": "傳送",
"Send a Message": "傳送訊息",
"Send message": "傳送訊息",
"September": "九月",
"Server connection verified": "已驗證伺服器連線",
"Set as default": "設為預設",
"Set Default Model": "設定預設模型",
"Set embedding model (e.g. {{model}})": "",
"Set embedding model (e.g. {{model}})": "設定嵌入模型(例如:{{model}})",
"Set Image Size": "設定圖片大小",
"Set Model": "設定模型",
"Set reranking model (e.g. {{model}})": "",
"Set reranking model (e.g. {{model}})": "設定重新排序模型(例如:{{model}})",
"Set Steps": "設定步數",
"Set Title Auto-Generation Model": "設定自動生成標題用模型",
"Set Voice": "設定語音",
......@@ -406,9 +397,8 @@
"Share to OpenWebUI Community": "分享到 OpenWebUI 社群",
"short-summary": "簡短摘要",
"Show": "顯示",
"Show Additional Params": "顯示額外參數",
"Show shortcuts": "顯示快速鍵",
"Showcased creativity": "",
"Showcased creativity": "展示創造性",
"sidebar": "側邊欄",
"Sign in": "登入",
"Sign Out": "登出",
......@@ -421,47 +411,47 @@
"Stop Sequence": "停止序列",
"STT Settings": "語音轉文字設定",
"Submit": "提交",
"Subtitle (e.g. about the Roman Empire)": "",
"Subtitle (e.g. about the Roman Empire)": "標題(例如:關於羅馬帝國)",
"Success": "成功",
"Successfully updated.": "更新成功。",
"Suggested": "建議",
"Sync All": "全部同步",
"System": "系統",
"System Prompt": "系統提示詞",
"Tags": "標籤",
"Tell us more:": "",
"Tell us more:": "告訴我們更多:",
"Temperature": "溫度",
"Template": "模板",
"Text Completion": "文本補全(Text Completion)",
"Text-to-Speech Engine": "文字轉語音引擎",
"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!": "感謝你的回饋!",
"The score should be a value between 0.0 (0%) and 1.0 (100%).": "分數應該介於 0.0(0%)和 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": "",
"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)": "",
"Title (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?": "存取 Ollama 時遇到問題?",
"TTS Settings": "文字轉語音設定",
"Type": "",
"Type Hugging Face Resolve (Download) URL": "輸入 Hugging Face 解析後的(下載)URL",
"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 and Copy Link": "更新並複製連結",
"Update password": "更新密碼",
"Upload a GGUF model": "上傳一個 GGUF 模型",
"Upload files": "上傳文件",
......@@ -469,35 +459,37 @@
"URL Mode": "URL 模式",
"Use '#' in the prompt input to load and select your documents.": "在輸入框中輸入 '#' 以載入並選擇你的文件。",
"Use Gravatar": "使用 Gravatar",
"Use Initials": "",
"Use Initials": "使用初始头像",
"user": "使用者",
"User Permissions": "使用者權限",
"Users": "使用者",
"Utilize": "使用",
"Valid time units:": "有效時間單位:",
"variable": "變數",
"variable to have them replaced with clipboard content.": "變數將替換為剪貼簿內容",
"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.": "",
"Warning": "",
"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 將會存取",
"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.": "當歷史被關閉時,這個瀏覽器上的新聊天將不會出現在任何裝置的歷史記錄中",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "當歷史被關閉時,這個瀏覽器上的新聊天將不會出現在任何裝置的歷史記錄中",
"Whisper (Local)": "Whisper(本機)",
"Workspace": "",
"Workspace": "工作區",
"Write a prompt suggestion (e.g. Who are you?)": "寫一個提示詞建議(例如:你是誰?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "寫一個 50 字的摘要來概括 [主題或關鍵詞]。",
"Yesterday": "",
"You": "",
"You have no archived conversations.": "",
"You have shared this chat": "",
"Yesterday": "昨天",
"You": "你",
"You cannot clone a base model": "",
"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": "Youtube",
"Youtube Loader Settings": "Youtube 載入器設定"
}
import { APP_NAME } from '$lib/constants';
import { type Writable, writable } from 'svelte/store';
import type { GlobalModelConfig, ModelConfig } from '$lib/apis';
import type { Banner } from '$lib/types';
// Backend
export const WEBUI_NAME = writable(APP_NAME);
......@@ -35,6 +37,8 @@ export const documents = writable([
}
]);
export const banners: Writable<Banner[]> = writable([]);
export const settings: Writable<Settings> = writable({});
export const showSidebar = writable(false);
......@@ -42,27 +46,27 @@ export const showSettings = writable(false);
export const showArchivedChats = writable(false);
export const showChangelog = writable(false);
type Model = OpenAIModel | OllamaModel;
export type Model = OpenAIModel | OllamaModel;
type OpenAIModel = {
type BaseModel = {
id: string;
name: string;
external: boolean;
source?: string;
info?: ModelConfig;
};
type OllamaModel = {
id: string;
name: string;
export interface OpenAIModel extends BaseModel {
external: boolean;
source?: string;
}
// Ollama specific fields
export interface OllamaModel extends BaseModel {
details: OllamaModelDetails;
size: number;
description: string;
model: string;
modified_at: string;
digest: string;
};
}
type OllamaModelDetails = {
parent_model: string;
......@@ -125,14 +129,20 @@ type Prompt = {
};
type Config = {
status?: boolean;
name?: string;
version?: string;
default_locale?: string;
images?: boolean;
default_models?: string[];
default_prompt_suggestions?: PromptSuggestion[];
trusted_header_auth?: boolean;
status: boolean;
name: string;
version: string;
default_locale: string;
default_models: string[];
default_prompt_suggestions: PromptSuggestion[];
features: {
auth: boolean;
enable_signup: boolean;
auth_trusted_header: boolean;
enable_image_generation: boolean;
enable_admin_export: boolean;
enable_community_sharing: boolean;
};
};
type PromptSuggestion = {
......
export type Banner = {
id: string;
type: string;
title?: string;
content: string;
url?: string;
dismissible?: boolean;
timestamp: number;
};
import { v4 as uuidv4 } from 'uuid';
import sha256 from 'js-sha256';
import { getOllamaModels } from '$lib/apis/ollama';
import { getOpenAIModels } from '$lib/apis/openai';
import { getLiteLLMModels } from '$lib/apis/litellm';
export const getModels = async (token: string) => {
let models = await Promise.all([
getOllamaModels(token).catch((error) => {
console.log(error);
return null;
}),
getOpenAIModels(token).catch((error) => {
console.log(error);
return null;
}),
getLiteLLMModels(token).catch((error) => {
console.log(error);
return null;
})
]);
models = models.filter((models) => models).reduce((a, e, i, arr) => a.concat(e), []);
return models;
};
//////////////////////////
// Helper functions
......@@ -36,11 +12,12 @@ export const sanitizeResponseContent = (content: string) => {
.replace(/<$/, '')
.replaceAll(/<\|[a-z]+\|>/g, ' ')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.trim();
};
export const revertSanitizedResponseContent = (content: string) => {
return content.replaceAll('&lt;', '<');
return content.replaceAll('&lt;', '<').replaceAll('&gt;', '>');
};
export const capitalizeFirstLetter = (string) => {
......
......@@ -7,9 +7,8 @@
import { goto } from '$app/navigation';
import { getModels as _getModels } from '$lib/utils';
import { getModels as _getModels } from '$lib/apis';
import { getOllamaVersion } from '$lib/apis/ollama';
import { getModelfiles } from '$lib/apis/modelfiles';
import { getPrompts } from '$lib/apis/prompts';
import { getDocs } from '$lib/apis/documents';
......@@ -20,10 +19,10 @@
showSettings,
settings,
models,
modelfiles,
prompts,
documents,
tags,
banners,
showChangelog,
config
} from '$lib/stores';
......@@ -35,6 +34,8 @@
import ShortcutsModal from '$lib/components/chat/ShortcutsModal.svelte';
import ChangelogModal from '$lib/components/ChangelogModal.svelte';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import { getBanners } from '$lib/apis/configs';
import { getUserSettings } from '$lib/apis/users';
const i18n = getContext('i18n');
......@@ -50,21 +51,6 @@
return _getModels(localStorage.token);
};
const setOllamaVersion = async (version: string = '') => {
if (version === '') {
version = await getOllamaVersion(localStorage.token).catch((error) => {
return '';
});
}
ollamaVersion = version;
console.log(ollamaVersion);
if (compareVersion(REQUIRED_OLLAMA_VERSION, ollamaVersion)) {
toast.error(`Ollama Version: ${ollamaVersion !== '' ? ollamaVersion : 'Not Detected'}`);
}
};
onMount(async () => {
if ($user === undefined) {
await goto('/auth');
......@@ -87,18 +73,31 @@
// IndexedDB Not Found
}
await models.set(await getModels());
await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
const userSettings = await getUserSettings(localStorage.token);
await modelfiles.set(await getModelfiles(localStorage.token));
await prompts.set(await getPrompts(localStorage.token));
await documents.set(await getDocs(localStorage.token));
await tags.set(await getAllChatTags(localStorage.token));
if (userSettings) {
await settings.set(userSettings.ui);
} else {
await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
}
modelfiles.subscribe(async () => {
// should fetch models
await models.set(await getModels());
});
await Promise.all([
(async () => {
models.set(await getModels());
})(),
(async () => {
prompts.set(await getPrompts(localStorage.token));
})(),
(async () => {
documents.set(await getDocs(localStorage.token));
})(),
(async () => {
banners.set(await getBanners(localStorage.token));
})(),
(async () => {
tags.set(await getAllChatTags(localStorage.token));
})()
]);
document.addEventListener('keydown', function (event) {
const isCtrlPressed = event.ctrlKey || event.metaKey; // metaKey is for Cmd key on Mac
......@@ -176,12 +175,12 @@
});
</script>
<div class=" hidden lg:flex fixed bottom-0 right-0 px-3 py-3 z-10">
<div class=" hidden lg:flex fixed bottom-0 right-0 px-2 py-2 z-10">
<Tooltip content={$i18n.t('Help')} placement="left">
<button
id="show-shortcuts-button"
bind:this={showShortcutsButtonElement}
class="text-gray-600 dark:text-gray-300 bg-gray-300/20 w-6 h-6 flex items-center justify-center text-xs rounded-full"
class="text-gray-600 dark:text-gray-300 bg-gray-300/20 size-5 flex items-center justify-center text-[0.7rem] rounded-full"
on:click={() => {
showShortcuts = !showShortcuts;
}}
......
<script lang="ts">
import { toast } from 'svelte-sonner';
import { v4 as uuidv4 } from 'uuid';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { getContext, onMount, tick } from 'svelte';
import {
WEBUI_NAME,
tags as _tags,
chatId,
chats,
config,
modelfiles,
models,
settings,
showSidebar,
user
} from '$lib/stores';
import { copyToClipboard, splitStream } from '$lib/utils';
import {
addTagById,
createNewChat,
deleteTagById,
getAllChatTags,
getChatList,
getTagsById,
updateChatById
} from '$lib/apis/chats';
import { cancelOllamaRequest, generateChatCompletion } from '$lib/apis/ollama';
import { generateOpenAIChatCompletion, generateTitle } from '$lib/apis/openai';
import { queryCollection, queryDoc } from '$lib/apis/rag';
import { queryMemory } from '$lib/apis/memories';
import { createOpenAITextStream } from '$lib/apis/streaming';
import MessageInput from '$lib/components/chat/MessageInput.svelte';
import Messages from '$lib/components/chat/Messages.svelte';
import ModelSelector from '$lib/components/chat/ModelSelector.svelte';
import Navbar from '$lib/components/layout/Navbar.svelte';
import {
LITELLM_API_BASE_URL,
OLLAMA_API_BASE_URL,
OPENAI_API_BASE_URL,
WEBUI_BASE_URL
} from '$lib/constants';
import { RAGTemplate } from '$lib/utils/rag';
const i18n = getContext('i18n');
let stopResponseFlag = false;
let autoScroll = true;
let processing = '';
let messagesContainerElement: HTMLDivElement;
let currentRequestId = null;
let showModelSelector = true;
let selectedModels = [''];
let atSelectedModel = '';
let selectedModelfile = null;
$: selectedModelfile =
selectedModels.length === 1 &&
$modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0]).length > 0
? $modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0])[0]
: null;
let selectedModelfiles = {};
$: selectedModelfiles = selectedModels.reduce((a, tagName, i, arr) => {
const modelfile =
$modelfiles.filter((modelfile) => modelfile.tagName === tagName)?.at(0) ?? undefined;
return {
...a,
...(modelfile && { [tagName]: modelfile })
};
}, {});
let chat = null;
let tags = [];
let title = '';
let prompt = '';
let files = [];
let messages = [];
let history = {
messages: {},
currentId: null
};
$: if (history.currentId !== null) {
let _messages = [];
let currentMessage = history.messages[history.currentId];
while (currentMessage !== null) {
_messages.unshift({ ...currentMessage });
currentMessage =
currentMessage.parentId !== null ? history.messages[currentMessage.parentId] : null;
}
messages = _messages;
} else {
messages = [];
}
onMount(async () => {
await initNewChat();
});
//////////////////////////
// Web functions
//////////////////////////
const initNewChat = async () => {
if (currentRequestId !== null) {
await cancelOllamaRequest(localStorage.token, currentRequestId);
currentRequestId = null;
}
window.history.replaceState(history.state, '', `/`);
await chatId.set('');
autoScroll = true;
title = '';
messages = [];
history = {
messages: {},
currentId: null
};
if ($page.url.searchParams.get('models')) {
selectedModels = $page.url.searchParams.get('models')?.split(',');
} else if ($settings?.models) {
selectedModels = $settings?.models;
} else if ($config?.default_models) {
selectedModels = $config?.default_models.split(',');
} else {
selectedModels = [''];
}
if ($page.url.searchParams.get('q')) {
prompt = $page.url.searchParams.get('q') ?? '';
if (prompt) {
await tick();
submitPrompt(prompt);
}
}
selectedModels = selectedModels.map((modelId) =>
$models.map((m) => m.id).includes(modelId) ? modelId : ''
);
let _settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
settings.set({
..._settings
});
const chatInput = document.getElementById('chat-textarea');
setTimeout(() => chatInput?.focus(), 0);
};
const scrollToBottom = async () => {
await tick();
if (messagesContainerElement) {
messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
}
};
//////////////////////////
// Ollama functions
//////////////////////////
const submitPrompt = async (userPrompt, _user = null) => {
console.log('submitPrompt', $chatId);
selectedModels = selectedModels.map((modelId) =>
$models.map((m) => m.id).includes(modelId) ? modelId : ''
);
if (selectedModels.includes('')) {
toast.error($i18n.t('Model not selected'));
} else if (messages.length != 0 && messages.at(-1).done != true) {
// Response not done
console.log('wait');
} else if (
files.length > 0 &&
files.filter((file) => file.upload_status === false).length > 0
) {
// Upload not done
toast.error(
$i18n.t(
`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.`
)
);
} else {
// Reset chat message textarea height
document.getElementById('chat-textarea').style.height = '';
// Create user message
let userMessageId = uuidv4();
let userMessage = {
id: userMessageId,
parentId: messages.length !== 0 ? messages.at(-1).id : null,
childrenIds: [],
role: 'user',
user: _user ?? undefined,
content: userPrompt,
files: files.length > 0 ? files : undefined,
models: selectedModels.filter((m, mIdx) => selectedModels.indexOf(m) === mIdx),
timestamp: Math.floor(Date.now() / 1000) // Unix epoch
};
// Add message to history and Set currentId to messageId
history.messages[userMessageId] = userMessage;
history.currentId = userMessageId;
// Append messageId to childrenIds of parent message
if (messages.length !== 0) {
history.messages[messages.at(-1).id].childrenIds.push(userMessageId);
}
// Wait until history/message have been updated
await tick();
// Create new chat if only one message in messages
if (messages.length == 1) {
if ($settings.saveChatHistory ?? true) {
chat = await createNewChat(localStorage.token, {
id: $chatId,
title: $i18n.t('New Chat'),
models: selectedModels,
system: $settings.system ?? undefined,
options: {
...($settings.options ?? {})
},
messages: messages,
history: history,
tags: [],
timestamp: Date.now()
});
await chats.set(await getChatList(localStorage.token));
await chatId.set(chat.id);
} else {
await chatId.set('local');
}
await tick();
}
// Reset chat input textarea
prompt = '';
files = [];
// Send prompt
await sendPrompt(userPrompt, userMessageId);
}
};
const sendPrompt = async (prompt, parentId, modelId = null) => {
const _chatId = JSON.parse(JSON.stringify($chatId));
await Promise.all(
(modelId ? [modelId] : atSelectedModel !== '' ? [atSelectedModel.id] : selectedModels).map(
async (modelId) => {
console.log('modelId', modelId);
const model = $models.filter((m) => m.id === modelId).at(0);
if (model) {
// Create response message
let responseMessageId = uuidv4();
let responseMessage = {
parentId: parentId,
id: responseMessageId,
childrenIds: [],
role: 'assistant',
content: '',
model: model.id,
userContext: null,
timestamp: Math.floor(Date.now() / 1000) // Unix epoch
};
// Add message to history and Set currentId to messageId
history.messages[responseMessageId] = responseMessage;
history.currentId = responseMessageId;
// Append messageId to childrenIds of parent message
if (parentId !== null) {
history.messages[parentId].childrenIds = [
...history.messages[parentId].childrenIds,
responseMessageId
];
}
await tick();
let userContext = null;
if ($settings?.memory ?? false) {
if (userContext === null) {
const res = await queryMemory(localStorage.token, prompt).catch((error) => {
toast.error(error);
return null;
});
if (res) {
if (res.documents[0].length > 0) {
userContext = res.documents.reduce((acc, doc, index) => {
const createdAtTimestamp = res.metadatas[index][0].created_at;
const createdAtDate = new Date(createdAtTimestamp * 1000)
.toISOString()
.split('T')[0];
acc.push(`${index + 1}. [${createdAtDate}]. ${doc[0]}`);
return acc;
}, []);
}
console.log(userContext);
}
}
}
responseMessage.userContext = userContext;
if (model?.external) {
await sendPromptOpenAI(model, prompt, responseMessageId, _chatId);
} else if (model) {
await sendPromptOllama(model, prompt, responseMessageId, _chatId);
}
} else {
toast.error($i18n.t(`Model {{modelId}} not found`, { modelId }));
}
}
)
);
await chats.set(await getChatList(localStorage.token));
};
const sendPromptOllama = async (model, userPrompt, responseMessageId, _chatId) => {
model = model.id;
const responseMessage = history.messages[responseMessageId];
// Wait until history/message have been updated
await tick();
// Scroll down
scrollToBottom();
const messagesBody = [
$settings.system || (responseMessage?.userContext ?? null)
? {
role: 'system',
content: `${$settings?.system ?? ''}${
responseMessage?.userContext ?? null
? `\n\nUser Context:\n${(responseMessage?.userContext ?? []).join('\n')}`
: ''
}`
}
: undefined,
...messages
]
.filter((message) => message)
.map((message, idx, arr) => {
// Prepare the base message object
const baseMessage = {
role: message.role,
content: arr.length - 2 !== idx ? message.content : message?.raContent ?? message.content
};
// Extract and format image URLs if any exist
const imageUrls = message.files
?.filter((file) => file.type === 'image')
.map((file) => file.url.slice(file.url.indexOf(',') + 1));
// Add images array only if it contains elements
if (imageUrls && imageUrls.length > 0 && message.role === 'user') {
baseMessage.images = imageUrls;
}
return baseMessage;
});
let lastImageIndex = -1;
// Find the index of the last object with images
messagesBody.forEach((item, index) => {
if (item.images) {
lastImageIndex = index;
}
});
// Remove images from all but the last one
messagesBody.forEach((item, index) => {
if (index !== lastImageIndex) {
delete item.images;
}
});
const docs = messages
.filter((message) => message?.files ?? null)
.map((message) =>
message.files.filter((item) => item.type === 'doc' || item.type === 'collection')
)
.flat(1);
const [res, controller] = await generateChatCompletion(localStorage.token, {
model: model,
messages: messagesBody,
options: {
...($settings.options ?? {}),
stop:
$settings?.options?.stop ?? undefined
? $settings.options.stop.map((str) =>
decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"'))
)
: undefined
},
format: $settings.requestFormat ?? undefined,
keep_alive: $settings.keepAlive ?? undefined,
docs: docs.length > 0 ? docs : undefined,
citations: docs.length > 0
});
if (res && res.ok) {
console.log('controller', controller);
const reader = res.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(splitStream('\n'))
.getReader();
while (true) {
const { value, done } = await reader.read();
if (done || stopResponseFlag || _chatId !== $chatId) {
responseMessage.done = true;
messages = messages;
if (stopResponseFlag) {
controller.abort('User: Stop Response');
await cancelOllamaRequest(localStorage.token, currentRequestId);
}
currentRequestId = null;
break;
}
try {
let lines = value.split('\n');
for (const line of lines) {
if (line !== '') {
console.log(line);
let data = JSON.parse(line);
if ('citations' in data) {
responseMessage.citations = data.citations;
continue;
}
if ('detail' in data) {
throw data;
}
if ('id' in data) {
console.log(data);
currentRequestId = data.id;
} else {
if (data.done == false) {
if (responseMessage.content == '' && data.message.content == '\n') {
continue;
} else {
responseMessage.content += data.message.content;
messages = messages;
}
} else {
responseMessage.done = true;
if (responseMessage.content == '') {
responseMessage.error = true;
responseMessage.content =
'Oops! No text generated from Ollama, Please try again.';
}
responseMessage.context = data.context ?? null;
responseMessage.info = {
total_duration: data.total_duration,
load_duration: data.load_duration,
sample_count: data.sample_count,
sample_duration: data.sample_duration,
prompt_eval_count: data.prompt_eval_count,
prompt_eval_duration: data.prompt_eval_duration,
eval_count: data.eval_count,
eval_duration: data.eval_duration
};
messages = messages;
if ($settings.notificationEnabled && !document.hasFocus()) {
const notification = new Notification(
selectedModelfile
? `${
selectedModelfile.title.charAt(0).toUpperCase() +
selectedModelfile.title.slice(1)
}`
: `${model}`,
{
body: responseMessage.content,
icon: selectedModelfile?.imageUrl ?? `${WEBUI_BASE_URL}/static/favicon.png`
}
);
}
if ($settings.responseAutoCopy) {
copyToClipboard(responseMessage.content);
}
if ($settings.responseAutoPlayback) {
await tick();
document.getElementById(`speak-button-${responseMessage.id}`)?.click();
}
}
}
}
}
} catch (error) {
console.log(error);
if ('detail' in error) {
toast.error(error.detail);
}
break;
}
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 {
toast.error(error.error);
responseMessage.content = error.error;
}
} else {
toast.error(
$i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { provider: 'Ollama' })
);
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: 'Ollama'
});
}
responseMessage.error = true;
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: 'Ollama'
});
responseMessage.done = true;
messages = messages;
}
stopResponseFlag = false;
await tick();
if (autoScroll) {
scrollToBottom();
}
if (messages.length == 2 && messages.at(1).content !== '') {
window.history.replaceState(history.state, '', `/c/${_chatId}`);
const _title = await generateChatTitle(userPrompt);
await setChatTitle(_chatId, _title);
}
};
const sendPromptOpenAI = async (model, userPrompt, responseMessageId, _chatId) => {
const responseMessage = history.messages[responseMessageId];
const docs = messages
.filter((message) => message?.files ?? null)
.map((message) =>
message.files.filter((item) => item.type === 'doc' || item.type === 'collection')
)
.flat(1);
console.log(docs);
scrollToBottom();
try {
const [res, controller] = await generateOpenAIChatCompletion(
localStorage.token,
{
model: model.id,
stream: true,
messages: [
$settings.system || (responseMessage?.userContext ?? null)
? {
role: 'system',
content: `${$settings?.system ?? ''}${
responseMessage?.userContext ?? null
? `\n\nUser Context:\n${(responseMessage?.userContext ?? []).join('\n')}`
: ''
}`
}
: undefined,
...messages
]
.filter((message) => message)
.filter((message) => message.content != '')
.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();
scrollToBottom();
if (res && res.ok && res.body) {
const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks);
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');
}
break;
}
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 {
await handleOpenAIError(null, res, model, responseMessage);
}
} catch (error) {
await handleOpenAIError(error, null, model, responseMessage);
}
messages = messages;
stopResponseFlag = false;
await tick();
if (autoScroll) {
scrollToBottom();
}
if (messages.length == 2) {
window.history.replaceState(history.state, '', `/c/${_chatId}`);
const _title = await generateChatTitle(userPrompt);
await setChatTitle(_chatId, _title);
}
};
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');
};
const regenerateResponse = async (message) => {
console.log('regenerateResponse');
if (messages.length != 0) {
let userMessage = history.messages[message.parentId];
let userPrompt = userMessage.content;
if ((userMessage?.models ?? [...selectedModels]).length == 1) {
await sendPrompt(userPrompt, userMessage.id);
} else {
await sendPrompt(userPrompt, userMessage.id, message.model);
}
}
};
const continueGeneration = async () => {
console.log('continueGeneration');
const _chatId = JSON.parse(JSON.stringify($chatId));
if (messages.length != 0 && messages.at(-1).done == true) {
const responseMessage = history.messages[history.currentId];
responseMessage.done = false;
await tick();
const model = $models.filter((m) => m.id === responseMessage.model).at(0);
if (model) {
if (model?.external) {
await sendPromptOpenAI(
model,
history.messages[responseMessage.parentId].content,
responseMessage.id,
_chatId
);
} else
await sendPromptOllama(
model,
history.messages[responseMessage.parentId].content,
responseMessage.id,
_chatId
);
}
} else {
toast.error($i18n.t(`Model {{modelId}} not found`, { modelId }));
}
};
const generateChatTitle = async (userPrompt) => {
if ($settings?.title?.auto ?? true) {
const model = $models.find((model) => model.id === selectedModels[0]);
const titleModelId =
model?.external ?? false
? $settings?.title?.modelExternal ?? selectedModels[0]
: $settings?.title?.model ?? selectedModels[0];
const titleModel = $models.find((model) => model.id === titleModelId);
console.log(titleModel);
const title = await generateTitle(
localStorage.token,
$settings?.title?.prompt ??
$i18n.t(
"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':"
) + ' {{prompt}}',
titleModelId,
userPrompt,
titleModel?.external ?? false
? titleModel?.source?.toLowerCase() === 'litellm'
? `${LITELLM_API_BASE_URL}/v1`
: `${OPENAI_API_BASE_URL}`
: `${OLLAMA_API_BASE_URL}/v1`
);
return title;
} else {
return `${userPrompt}`;
}
};
const setChatTitle = async (_chatId, _title) => {
if (_chatId === $chatId) {
title = _title;
}
if ($settings.saveChatHistory ?? true) {
chat = await updateChatById(localStorage.token, _chatId, { title: _title });
await chats.set(await getChatList(localStorage.token));
}
};
const getTags = async () => {
return await getTagsById(localStorage.token, $chatId).catch(async (error) => {
return [];
});
};
const addTag = async (tagName) => {
const res = await addTagById(localStorage.token, $chatId, tagName);
tags = await getTags();
chat = await updateChatById(localStorage.token, $chatId, {
tags: tags
});
_tags.set(await getAllChatTags(localStorage.token));
};
const deleteTag = async (tagName) => {
const res = await deleteTagById(localStorage.token, $chatId, tagName);
tags = await getTags();
chat = await updateChatById(localStorage.token, $chatId, {
tags: tags
});
_tags.set(await getAllChatTags(localStorage.token));
};
import Chat from '$lib/components/chat/Chat.svelte';
</script>
<svelte:head>
<title>
{title
? `${title.length > 30 ? `${title.slice(0, 30)}...` : title} | ${$WEBUI_NAME}`
: `${$WEBUI_NAME}`}
</title>
</svelte:head>
<div
class="min-h-screen max-h-screen {$showSidebar
? 'md:max-w-[calc(100%-260px)]'
: ''} w-full max-w-full flex flex-col"
>
<Navbar
{title}
bind:selectedModels
bind:showModelSelector
shareEnabled={messages.length > 0}
{chat}
{initNewChat}
/>
<div class="flex flex-col flex-auto">
<div
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full"
id="messages-container"
bind:this={messagesContainerElement}
on:scroll={(e) => {
autoScroll =
messagesContainerElement.scrollHeight - messagesContainerElement.scrollTop <=
messagesContainerElement.clientHeight + 5;
}}
>
<div class=" h-full w-full flex flex-col pt-2 pb-4">
<Messages
chatId={$chatId}
{selectedModels}
{selectedModelfiles}
{processing}
bind:history
bind:messages
bind:autoScroll
bind:prompt
bottomPadding={files.length > 0}
suggestionPrompts={selectedModelfile?.suggestionPrompts ??
$config.default_prompt_suggestions}
{sendPrompt}
{continueGeneration}
{regenerateResponse}
/>
</div>
</div>
</div>
</div>
<MessageInput
bind:files
bind:prompt
bind:autoScroll
bind:selectedModel={atSelectedModel}
{messages}
{submitPrompt}
{stopResponse}
/>
<Chat />
<script lang="ts">
import { onMount, getContext } from 'svelte';
import { WEBUI_NAME, showSidebar } from '$lib/stores';
import MenuLines from '$lib/components/icons/MenuLines.svelte';
import { page } from '$app/stores';
const i18n = getContext('i18n');
</script>
<svelte:head>
<title>
{$i18n.t('Admin Panel')} | {$WEBUI_NAME}
</title>
</svelte:head>
<div class=" flex flex-col w-full min-h-screen max-h-screen">
<div class=" px-4 pt-3 mt-0.5 mb-1">
<div class=" flex items-center gap-1">
<div class="{$showSidebar ? 'md:hidden' : ''} mr-1 self-start flex flex-none items-center">
<button
id="sidebar-toggle-button"
class="cursor-pointer p-1 flex rounded-xl hover:bg-gray-100 dark:hover:bg-gray-850 transition"
on:click={() => {
showSidebar.set(!$showSidebar);
}}
>
<div class=" m-auto self-center">
<MenuLines />
</div>
</button>
</div>
<div class="flex items-center text-xl font-semibold">{$i18n.t('Workspace')}</div>
</div>
</div>
<!-- <div class="px-4 my-1">
<div
class="flex scrollbar-none overflow-x-auto w-fit text-center text-sm font-medium rounded-xl bg-transparent/10 p-1"
>
<a
class="min-w-fit rounded-lg p-1.5 px-3 {$page.url.pathname.includes('/workspace/models')
? 'bg-gray-50 dark:bg-gray-850'
: ''} transition"
href="/workspace/models">{$i18n.t('Models')}</a
>
<a
class="min-w-fit rounded-lg p-1.5 px-3 {$page.url.pathname.includes('/workspace/prompts')
? 'bg-gray-50 dark:bg-gray-850'
: ''} transition"
href="/workspace/prompts">{$i18n.t('Prompts')}</a
>
<a
class="min-w-fit rounded-lg p-1.5 px-3 {$page.url.pathname.includes('/workspace/documents')
? 'bg-gray-50 dark:bg-gray-850'
: ''} transition"
href="/workspace/documents"
>
{$i18n.t('Documents')}
</a>
<a
class="min-w-fit rounded-lg p-1.5 px-3 {$page.url.pathname.includes('/workspace/playground')
? 'bg-gray-50 dark:bg-gray-850'
: ''} transition"
href="/workspace/playground">{$i18n.t('Playground')}</a
>
</div>
</div> -->
<hr class=" my-2 dark:border-gray-850" />
<div class=" py-1 px-5 flex-1 max-h-full overflow-y-auto">
<slot />
</div>
</div>
......@@ -82,10 +82,6 @@
});
</script>
<svelte:head>
<title>{$i18n.t('Admin Panel')} | {$WEBUI_NAME}</title>
</svelte:head>
{#key selectedUser}
<EditUserModal
bind:show={showEditUserModal}
......@@ -106,265 +102,222 @@
<UserChatsModal bind:show={showUserChatsModal} user={selectedUser} />
<SettingsModal bind:show={showSettingsModal} />
<div class=" flex flex-col w-full min-h-screen">
{#if loaded}
<div class="px-4 pt-3 mt-0.5 mb-1">
<div class=" flex items-center gap-1">
<div class="{$showSidebar ? 'md:hidden' : ''} mr-1 self-start flex flex-none items-center">
{#if loaded}
<div class="mt-0.5 mb-3 gap-1 flex flex-col md:flex-row justify-between">
<div class="flex md:self-center text-lg font-medium px-0.5">
{$i18n.t('All Users')}
<div class="flex self-center w-[1px] h-6 mx-2.5 bg-gray-200 dark:bg-gray-700" />
<span class="text-lg font-medium text-gray-500 dark:text-gray-300">{users.length}</span>
</div>
<div class="flex gap-1">
<input
class="w-full md:w-60 rounded-xl py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
placeholder={$i18n.t('Search')}
bind:value={search}
/>
<div class="flex gap-0.5">
<Tooltip content="Add User">
<button
id="sidebar-toggle-button"
class="cursor-pointer p-1 flex rounded-xl hover:bg-gray-100 dark:hover:bg-gray-850 transition"
class=" px-2 py-2 rounded-xl border border-gray-200 dark:border-gray-600 dark:border-0 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition font-medium text-sm flex items-center space-x-1"
on:click={() => {
showSidebar.set(!$showSidebar);
showAddUserModal = !showAddUserModal;
}}
>
<div class=" m-auto self-center">
<MenuLines />
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
/>
</svg>
</button>
</div>
<div class="flex items-center text-xl font-semibold">{$i18n.t('Dashboard')}</div>
</div>
</div>
</Tooltip>
<!-- <div class="px-4 my-1">
<div
class="flex scrollbar-none overflow-x-auto w-fit text-center text-sm font-medium rounded-xl bg-transparent/10 p-1"
>
<button
class="min-w-fit rounded-lg p-1.5 px-3 {tab === ''
? 'bg-gray-50 dark:bg-gray-850'
: ''} transition"
type="button"
on:click={() => {
tab = '';
}}>{$i18n.t('Overview')}</button
>
<Tooltip content={$i18n.t('Admin Settings')}>
<button
class=" px-2 py-2 rounded-xl border border-gray-200 dark:border-gray-600 dark:border-0 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition font-medium text-sm flex items-center space-x-1"
on:click={() => {
showSettingsModal = !showSettingsModal;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
fill-rule="evenodd"
d="M6.955 1.45A.5.5 0 0 1 7.452 1h1.096a.5.5 0 0 1 .497.45l.17 1.699c.484.12.94.312 1.356.562l1.321-1.081a.5.5 0 0 1 .67.033l.774.775a.5.5 0 0 1 .034.67l-1.08 1.32c.25.417.44.873.561 1.357l1.699.17a.5.5 0 0 1 .45.497v1.096a.5.5 0 0 1-.45.497l-1.699.17c-.12.484-.312.94-.562 1.356l1.082 1.322a.5.5 0 0 1-.034.67l-.774.774a.5.5 0 0 1-.67.033l-1.322-1.08c-.416.25-.872.44-1.356.561l-.17 1.699a.5.5 0 0 1-.497.45H7.452a.5.5 0 0 1-.497-.45l-.17-1.699a4.973 4.973 0 0 1-1.356-.562L4.108 13.37a.5.5 0 0 1-.67-.033l-.774-.775a.5.5 0 0 1-.034-.67l1.08-1.32a4.971 4.971 0 0 1-.561-1.357l-1.699-.17A.5.5 0 0 1 1 8.548V7.452a.5.5 0 0 1 .45-.497l1.699-.17c.12-.484.312-.94.562-1.356L2.629 4.107a.5.5 0 0 1 .034-.67l.774-.774a.5.5 0 0 1 .67-.033L5.43 3.71a4.97 4.97 0 0 1 1.356-.561l.17-1.699ZM6 8c0 .538.212 1.026.558 1.385l.057.057a2 2 0 0 0 2.828-2.828l-.058-.056A2 2 0 0 0 6 8Z"
clip-rule="evenodd"
/>
</svg>
</button>
</Tooltip>
</div>
</div> -->
<hr class=" my-2 dark:border-gray-850" />
<div class="px-6">
<div class="mt-0.5 mb-3 gap-1 flex flex-col md:flex-row justify-between">
<div class="flex md:self-center text-lg font-medium px-0.5">
{$i18n.t('All Users')}
<div class="flex self-center w-[1px] h-6 mx-2.5 bg-gray-200 dark:bg-gray-700" />
<span class="text-lg font-medium text-gray-500 dark:text-gray-300">{users.length}</span>
</div>
<div class="flex gap-1">
<input
class="w-full md:w-60 rounded-xl py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
placeholder={$i18n.t('Search')}
bind:value={search}
/>
<div class="flex gap-0.5">
<Tooltip content="Add User">
</div>
</div>
<div class="scrollbar-hidden relative whitespace-nowrap overflow-x-auto max-w-full">
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400 table-auto max-w-full">
<thead class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-850 dark:text-gray-400">
<tr>
<th scope="col" class="px-3 py-2"> {$i18n.t('Role')} </th>
<th scope="col" class="px-3 py-2"> {$i18n.t('Name')} </th>
<th scope="col" class="px-3 py-2"> {$i18n.t('Email')} </th>
<th scope="col" class="px-3 py-2"> {$i18n.t('Last Active')} </th>
<th scope="col" class="px-3 py-2"> {$i18n.t('Created at')} </th>
<th scope="col" class="px-3 py-2 text-right" />
</tr>
</thead>
<tbody>
{#each users
.filter((user) => {
if (search === '') {
return true;
} else {
let name = user.name.toLowerCase();
const query = search.toLowerCase();
return name.includes(query);
}
})
.slice((page - 1) * 20, page * 20) as user}
<tr class="bg-white border-b dark:bg-gray-900 dark:border-gray-700 text-xs">
<td class="px-3 py-2 min-w-[7rem] w-28">
<button
class=" px-2 py-2 rounded-xl border border-gray-200 dark:border-gray-600 dark:border-0 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition font-medium text-sm flex items-center space-x-1"
class=" flex items-center gap-2 text-xs px-3 py-0.5 rounded-lg {user.role ===
'admin' && 'text-sky-600 dark:text-sky-200 bg-sky-200/30'} {user.role ===
'user' && 'text-green-600 dark:text-green-200 bg-green-200/30'} {user.role ===
'pending' && 'text-gray-600 dark:text-gray-200 bg-gray-200/30'}"
on:click={() => {
showAddUserModal = !showAddUserModal;
if (user.role === 'user') {
updateRoleHandler(user.id, 'admin');
} else if (user.role === 'pending') {
updateRoleHandler(user.id, 'user');
} else {
updateRoleHandler(user.id, 'pending');
}
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
/>
</svg>
</button>
</Tooltip>
<Tooltip content={$i18n.t('Admin Settings')}>
<button
class=" px-2 py-2 rounded-xl border border-gray-200 dark:border-gray-600 dark:border-0 hover:bg-gray-100 dark:bg-gray-850 dark:hover:bg-gray-800 transition font-medium text-sm flex items-center space-x-1"
on:click={() => {
showSettingsModal = !showSettingsModal;
}}
<div
class="w-1 h-1 rounded-full {user.role === 'admin' &&
'bg-sky-600 dark:bg-sky-300'} {user.role === 'user' &&
'bg-green-600 dark:bg-green-300'} {user.role === 'pending' &&
'bg-gray-600 dark:bg-gray-300'}"
/>
{$i18n.t(user.role)}</button
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
fill-rule="evenodd"
d="M6.955 1.45A.5.5 0 0 1 7.452 1h1.096a.5.5 0 0 1 .497.45l.17 1.699c.484.12.94.312 1.356.562l1.321-1.081a.5.5 0 0 1 .67.033l.774.775a.5.5 0 0 1 .034.67l-1.08 1.32c.25.417.44.873.561 1.357l1.699.17a.5.5 0 0 1 .45.497v1.096a.5.5 0 0 1-.45.497l-1.699.17c-.12.484-.312.94-.562 1.356l1.082 1.322a.5.5 0 0 1-.034.67l-.774.774a.5.5 0 0 1-.67.033l-1.322-1.08c-.416.25-.872.44-1.356.561l-.17 1.699a.5.5 0 0 1-.497.45H7.452a.5.5 0 0 1-.497-.45l-.17-1.699a4.973 4.973 0 0 1-1.356-.562L4.108 13.37a.5.5 0 0 1-.67-.033l-.774-.775a.5.5 0 0 1-.034-.67l1.08-1.32a4.971 4.971 0 0 1-.561-1.357l-1.699-.17A.5.5 0 0 1 1 8.548V7.452a.5.5 0 0 1 .45-.497l1.699-.17c.12-.484.312-.94.562-1.356L2.629 4.107a.5.5 0 0 1 .034-.67l.774-.774a.5.5 0 0 1 .67-.033L5.43 3.71a4.97 4.97 0 0 1 1.356-.561l.17-1.699ZM6 8c0 .538.212 1.026.558 1.385l.057.057a2 2 0 0 0 2.828-2.828l-.058-.056A2 2 0 0 0 6 8Z"
clip-rule="evenodd"
/>
</svg>
</button>
</Tooltip>
</div>
</div>
</div>
<div class="scrollbar-hidden relative overflow-x-auto whitespace-nowrap">
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400 table-auto">
<thead
class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-850 dark:text-gray-400"
>
<tr>
<th scope="col" class="px-3 py-2"> {$i18n.t('Role')} </th>
<th scope="col" class="px-3 py-2"> {$i18n.t('Name')} </th>
<th scope="col" class="px-3 py-2"> {$i18n.t('Email')} </th>
<th scope="col" class="px-3 py-2"> {$i18n.t('Last Active')} </th>
<th scope="col" class="px-3 py-2"> {$i18n.t('Created at')} </th>
<th scope="col" class="px-3 py-2 text-right" />
</tr>
</thead>
<tbody>
{#each users
.filter((user) => {
if (search === '') {
return true;
} else {
let name = user.name.toLowerCase();
const query = search.toLowerCase();
return name.includes(query);
}
})
.slice((page - 1) * 20, page * 20) as user}
<tr class="bg-white border-b dark:bg-gray-900 dark:border-gray-700 text-xs">
<td class="px-3 py-2 min-w-[7rem] w-28">
<button
class=" flex items-center gap-2 text-xs px-3 py-0.5 rounded-lg {user.role ===
'admin' && 'text-sky-600 dark:text-sky-200 bg-sky-200/30'} {user.role ===
'user' && 'text-green-600 dark:text-green-200 bg-green-200/30'} {user.role ===
'pending' && 'text-gray-600 dark:text-gray-200 bg-gray-200/30'}"
on:click={() => {
if (user.role === 'user') {
updateRoleHandler(user.id, 'admin');
} else if (user.role === 'pending') {
updateRoleHandler(user.id, 'user');
} else {
updateRoleHandler(user.id, 'pending');
}
}}
>
<div
class="w-1 h-1 rounded-full {user.role === 'admin' &&
'bg-sky-600 dark:bg-sky-300'} {user.role === 'user' &&
'bg-green-600 dark:bg-green-300'} {user.role === 'pending' &&
'bg-gray-600 dark:bg-gray-300'}"
/>
{$i18n.t(user.role)}</button
>
</td>
<td class="px-3 py-2 font-medium text-gray-900 dark:text-white w-max">
<div class="flex flex-row w-max">
<img
class=" rounded-full w-6 h-6 object-cover mr-2.5"
src={user.profile_image_url.startsWith(WEBUI_BASE_URL) ||
user.profile_image_url.startsWith('https://www.gravatar.com/avatar/') ||
user.profile_image_url.startsWith('data:')
? user.profile_image_url
: `/user.png`}
alt="user"
/>
<div class=" font-medium self-center">{user.name}</div>
</div>
</td>
<td class=" px-3 py-2"> {user.email} </td>
<td class=" px-3 py-2">
{dayjs(user.last_active_at * 1000).fromNow()}
</td>
<td class=" px-3 py-2">
{dayjs(user.created_at * 1000).format($i18n.t('MMMM DD, YYYY'))}
</td>
<td class="px-3 py-2 text-right">
<div class="flex justify-end w-full">
{#if user.role !== 'admin'}
<Tooltip content={$i18n.t('Chats')}>
<button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => {
showUserChatsModal = !showUserChatsModal;
selectedUser = user;
}}
>
<ChatBubbles />
</button>
</Tooltip>
<Tooltip content={$i18n.t('Edit User')}>
<button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => {
showEditUserModal = !showEditUserModal;
selectedUser = user;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"
/>
</svg>
</button>
</Tooltip>
<Tooltip content={$i18n.t('Delete User')}>
<button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => {
deleteUserHandler(user.id);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
/>
</svg>
</button>
</Tooltip>
{/if}
</div>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
<div class=" text-gray-500 text-xs mt-2 text-right">
ⓘ {$i18n.t("Click on the user role button to change a user's role.")}
</div>
<Pagination bind:page count={users.length} />
</div>
{/if}
</div>
</td>
<td class="px-3 py-2 font-medium text-gray-900 dark:text-white w-max">
<div class="flex flex-row w-max">
<img
class=" rounded-full w-6 h-6 object-cover mr-2.5"
src={user.profile_image_url.startsWith(WEBUI_BASE_URL) ||
user.profile_image_url.startsWith('https://www.gravatar.com/avatar/') ||
user.profile_image_url.startsWith('data:')
? user.profile_image_url
: `/user.png`}
alt="user"
/>
<div class=" font-medium self-center">{user.name}</div>
</div>
</td>
<td class=" px-3 py-2"> {user.email} </td>
<td class=" px-3 py-2">
{dayjs(user.last_active_at * 1000).fromNow()}
</td>
<td class=" px-3 py-2">
{dayjs(user.created_at * 1000).format($i18n.t('MMMM DD, YYYY'))}
</td>
<td class="px-3 py-2 text-right">
<div class="flex justify-end w-full">
{#if user.role !== 'admin'}
<Tooltip content={$i18n.t('Chats')}>
<button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => {
showUserChatsModal = !showUserChatsModal;
selectedUser = user;
}}
>
<ChatBubbles />
</button>
</Tooltip>
<Tooltip content={$i18n.t('Edit User')}>
<button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => {
showEditUserModal = !showEditUserModal;
selectedUser = user;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"
/>
</svg>
</button>
</Tooltip>
<Tooltip content={$i18n.t('Delete User')}>
<button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => {
deleteUserHandler(user.id);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
/>
</svg>
</button>
</Tooltip>
{/if}
</div>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
<div class=" text-gray-500 text-xs mt-2 text-right">
ⓘ {$i18n.t("Click on the user role button to change a user's role.")}
</div>
<Pagination bind:page count={users.length} />
{/if}
<style>
.font-mona {
......
<script lang="ts">
import { toast } from 'svelte-sonner';
import { v4 as uuidv4 } from 'uuid';
import { goto } from '$app/navigation';
import Chat from '$lib/components/chat/Chat.svelte';
import { page } from '$app/stores';
import {
WEBUI_NAME,
tags as _tags,
chatId,
chats,
config,
modelfiles,
models,
settings,
showSidebar,
user
} from '$lib/stores';
import { convertMessagesToHistory, copyToClipboard, splitStream } from '$lib/utils';
import { getContext, onMount, tick } from 'svelte';
import {
addTagById,
createNewChat,
deleteTagById,
getAllChatTags,
getChatById,
getChatList,
getTagsById,
updateChatById
} from '$lib/apis/chats';
import { cancelOllamaRequest, generateChatCompletion } from '$lib/apis/ollama';
import { generateOpenAIChatCompletion, generateTitle } from '$lib/apis/openai';
import MessageInput from '$lib/components/chat/MessageInput.svelte';
import Messages from '$lib/components/chat/Messages.svelte';
import Navbar from '$lib/components/layout/Navbar.svelte';
import { queryMemory } from '$lib/apis/memories';
import { createOpenAITextStream } from '$lib/apis/streaming';
import {
LITELLM_API_BASE_URL,
OLLAMA_API_BASE_URL,
OPENAI_API_BASE_URL,
WEBUI_BASE_URL
} from '$lib/constants';
const i18n = getContext('i18n');
let loaded = false;
let stopResponseFlag = false;
let autoScroll = true;
let processing = '';
let messagesContainerElement: HTMLDivElement;
let currentRequestId = null;
// let chatId = $page.params.id;
let showModelSelector = true;
let selectedModels = [''];
let atSelectedModel = '';
let selectedModelfile = null;
$: selectedModelfile =
selectedModels.length === 1 &&
$modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0]).length > 0
? $modelfiles.filter((modelfile) => modelfile.tagName === selectedModels[0])[0]
: null;
let selectedModelfiles = {};
$: selectedModelfiles = selectedModels.reduce((a, tagName, i, arr) => {
const modelfile =
$modelfiles.filter((modelfile) => modelfile.tagName === tagName)?.at(0) ?? undefined;
return {
...a,
...(modelfile && { [tagName]: modelfile })
};
}, {});
let chat = null;
let tags = [];
let title = '';
let prompt = '';
let files = [];
let messages = [];
let history = {
messages: {},
currentId: null
};
$: if (history.currentId !== null) {
let _messages = [];
let currentMessage = history.messages[history.currentId];
while (currentMessage !== null) {
_messages.unshift({ ...currentMessage });
currentMessage =
currentMessage.parentId !== null ? history.messages[currentMessage.parentId] : null;
}
messages = _messages;
} else {
messages = [];
}
$: if ($page.params.id) {
(async () => {
if (await loadChat()) {
await tick();
loaded = true;
window.setTimeout(() => scrollToBottom(), 0);
const chatInput = document.getElementById('chat-textarea');
chatInput?.focus();
} else {
await goto('/');
}
})();
}
//////////////////////////
// Web functions
//////////////////////////
const loadChat = async () => {
await chatId.set($page.params.id);
chat = await getChatById(localStorage.token, $chatId).catch(async (error) => {
await goto('/');
return null;
});
if (chat) {
tags = await getTags();
const chatContent = chat.chat;
if (chatContent) {
console.log(chatContent);
selectedModels =
(chatContent?.models ?? undefined) !== undefined
? chatContent.models
: [chatContent.models ?? ''];
history =
(chatContent?.history ?? undefined) !== undefined
? chatContent.history
: convertMessagesToHistory(chatContent.messages);
title = chatContent.title;
let _settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
await settings.set({
..._settings,
system: chatContent.system ?? _settings.system,
options: chatContent.options ?? _settings.options
});
autoScroll = true;
await tick();
if (messages.length > 0) {
history.messages[messages.at(-1).id].done = true;
}
await tick();
return true;
} else {
return null;
}
}
};
const scrollToBottom = async () => {
await tick();
if (messagesContainerElement) {
messagesContainerElement.scrollTop = messagesContainerElement.scrollHeight;
}
};
//////////////////////////
// Ollama functions
//////////////////////////
const submitPrompt = async (userPrompt, _user = null) => {
console.log('submitPrompt', $chatId);
if (selectedModels.includes('')) {
toast.error($i18n.t('Model not selected'));
} else if (messages.length != 0 && messages.at(-1).done != true) {
// Response not done
console.log('wait');
} else if (
files.length > 0 &&
files.filter((file) => file.upload_status === false).length > 0
) {
// Upload not done
toast.error(
`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.`
);
} else {
// Reset chat message textarea height
document.getElementById('chat-textarea').style.height = '';
// Create user message
let userMessageId = uuidv4();
let userMessage = {
id: userMessageId,
parentId: messages.length !== 0 ? messages.at(-1).id : null,
childrenIds: [],
role: 'user',
user: _user ?? undefined,
content: userPrompt,
files: files.length > 0 ? files : undefined,
timestamp: Math.floor(Date.now() / 1000), // Unix epoch
models: selectedModels
};
// Add message to history and Set currentId to messageId
history.messages[userMessageId] = userMessage;
history.currentId = userMessageId;
// Append messageId to childrenIds of parent message
if (messages.length !== 0) {
history.messages[messages.at(-1).id].childrenIds.push(userMessageId);
}
// Wait until history/message have been updated
await tick();
// Create new chat if only one message in messages
if (messages.length == 1) {
if ($settings.saveChatHistory ?? true) {
chat = await createNewChat(localStorage.token, {
id: $chatId,
title: $i18n.t('New Chat'),
models: selectedModels,
system: $settings.system ?? undefined,
options: {
...($settings.options ?? {})
},
messages: messages,
history: history,
timestamp: Date.now()
});
await chats.set(await getChatList(localStorage.token));
await chatId.set(chat.id);
} else {
await chatId.set('local');
}
await tick();
}
// Reset chat input textarea
prompt = '';
files = [];
// Send prompt
await sendPrompt(userPrompt, userMessageId);
}
};
const sendPrompt = async (prompt, parentId, modelId = null) => {
const _chatId = JSON.parse(JSON.stringify($chatId));
await Promise.all(
(modelId ? [modelId] : atSelectedModel !== '' ? [atSelectedModel.id] : selectedModels).map(
async (modelId) => {
console.log('modelId', modelId);
const model = $models.filter((m) => m.id === modelId).at(0);
if (model) {
// Create response message
let responseMessageId = uuidv4();
let responseMessage = {
parentId: parentId,
id: responseMessageId,
childrenIds: [],
role: 'assistant',
content: '',
model: model.id,
userContext: null,
timestamp: Math.floor(Date.now() / 1000) // Unix epoch
};
// Add message to history and Set currentId to messageId
history.messages[responseMessageId] = responseMessage;
history.currentId = responseMessageId;
// Append messageId to childrenIds of parent message
if (parentId !== null) {
history.messages[parentId].childrenIds = [
...history.messages[parentId].childrenIds,
responseMessageId
];
}
await tick();
let userContext = null;
if ($settings?.memory ?? false) {
if (userContext === null) {
const res = await queryMemory(localStorage.token, prompt).catch((error) => {
toast.error(error);
return null;
});
if (res) {
if (res.documents[0].length > 0) {
userContext = res.documents.reduce((acc, doc, index) => {
const createdAtTimestamp = res.metadatas[index][0].created_at;
const createdAtDate = new Date(createdAtTimestamp * 1000)
.toISOString()
.split('T')[0];
acc.push(`${index + 1}. [${createdAtDate}]. ${doc[0]}`);
return acc;
}, []);
}
console.log(userContext);
}
}
}
responseMessage.userContext = userContext;
if (model?.external) {
await sendPromptOpenAI(model, prompt, responseMessageId, _chatId);
} else if (model) {
await sendPromptOllama(model, prompt, responseMessageId, _chatId);
}
} else {
toast.error($i18n.t(`Model {{modelId}} not found`, { modelId }));
}
}
)
);
await chats.set(await getChatList(localStorage.token));
};
const sendPromptOllama = async (model, userPrompt, responseMessageId, _chatId) => {
model = model.id;
const responseMessage = history.messages[responseMessageId];
// Wait until history/message have been updated
await tick();
// Scroll down
scrollToBottom();
const messagesBody = [
$settings.system || (responseMessage?.userContext ?? null)
? {
role: 'system',
content: `${$settings?.system ?? ''}${
responseMessage?.userContext ?? null
? `\n\nUser Context:\n${(responseMessage?.userContext ?? []).join('\n')}`
: ''
}`
}
: undefined,
...messages
]
.filter((message) => message)
.map((message, idx, arr) => {
// Prepare the base message object
const baseMessage = {
role: message.role,
content: arr.length - 2 !== idx ? message.content : message?.raContent ?? message.content
};
// Extract and format image URLs if any exist
const imageUrls = message.files
?.filter((file) => file.type === 'image')
.map((file) => file.url.slice(file.url.indexOf(',') + 1));
// Add images array only if it contains elements
if (imageUrls && imageUrls.length > 0 && message.role === 'user') {
baseMessage.images = imageUrls;
}
return baseMessage;
});
let lastImageIndex = -1;
// Find the index of the last object with images
messagesBody.forEach((item, index) => {
if (item.images) {
lastImageIndex = index;
}
});
// Remove images from all but the last one
messagesBody.forEach((item, index) => {
if (index !== lastImageIndex) {
delete item.images;
}
});
const docs = messages
.filter((message) => message?.files ?? null)
.map((message) =>
message.files.filter((item) => item.type === 'doc' || item.type === 'collection')
)
.flat(1);
const [res, controller] = await generateChatCompletion(localStorage.token, {
model: model,
messages: messagesBody,
options: {
...($settings.options ?? {}),
stop:
$settings?.options?.stop ?? undefined
? $settings.options.stop.map((str) =>
decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"'))
)
: undefined
},
format: $settings.requestFormat ?? undefined,
keep_alive: $settings.keepAlive ?? undefined,
docs: docs.length > 0 ? docs : undefined,
citations: docs.length > 0
});
if (res && res.ok) {
console.log('controller', controller);
const reader = res.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(splitStream('\n'))
.getReader();
while (true) {
const { value, done } = await reader.read();
if (done || stopResponseFlag || _chatId !== $chatId) {
responseMessage.done = true;
messages = messages;
if (stopResponseFlag) {
controller.abort('User: Stop Response');
await cancelOllamaRequest(localStorage.token, currentRequestId);
}
currentRequestId = null;
break;
}
try {
let lines = value.split('\n');
for (const line of lines) {
if (line !== '') {
console.log(line);
let data = JSON.parse(line);
if ('citations' in data) {
responseMessage.citations = data.citations;
continue;
}
if ('detail' in data) {
throw data;
}
if ('id' in data) {
console.log(data);
currentRequestId = data.id;
} else {
if (data.done == false) {
if (responseMessage.content == '' && data.message.content == '\n') {
continue;
} else {
responseMessage.content += data.message.content;
messages = messages;
}
} else {
responseMessage.done = true;
if (responseMessage.content == '') {
responseMessage.error = true;
responseMessage.content =
'Oops! No text generated from Ollama, Please try again.';
}
responseMessage.context = data.context ?? null;
responseMessage.info = {
total_duration: data.total_duration,
load_duration: data.load_duration,
sample_count: data.sample_count,
sample_duration: data.sample_duration,
prompt_eval_count: data.prompt_eval_count,
prompt_eval_duration: data.prompt_eval_duration,
eval_count: data.eval_count,
eval_duration: data.eval_duration
};
messages = messages;
if ($settings.notificationEnabled && !document.hasFocus()) {
const notification = new Notification(
selectedModelfile
? `${
selectedModelfile.title.charAt(0).toUpperCase() +
selectedModelfile.title.slice(1)
}`
: `${model}`,
{
body: responseMessage.content,
icon: selectedModelfile?.imageUrl ?? `${WEBUI_BASE_URL}/static/favicon.png`
}
);
}
if ($settings.responseAutoCopy) {
copyToClipboard(responseMessage.content);
}
if ($settings.responseAutoPlayback) {
await tick();
document.getElementById(`speak-button-${responseMessage.id}`)?.click();
}
}
}
}
}
} catch (error) {
console.log(error);
if ('detail' in error) {
toast.error(error.detail);
}
break;
}
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 {
toast.error(error.error);
responseMessage.content = error.error;
}
} else {
toast.error(
$i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, { provider: 'Ollama' })
);
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: 'Ollama'
});
}
responseMessage.error = true;
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: 'Ollama'
});
responseMessage.done = true;
messages = messages;
}
stopResponseFlag = false;
await tick();
if (autoScroll) {
scrollToBottom();
}
if (messages.length == 2 && messages.at(1).content !== '') {
window.history.replaceState(history.state, '', `/c/${_chatId}`);
const _title = await generateChatTitle(userPrompt);
await setChatTitle(_chatId, _title);
}
};
const sendPromptOpenAI = async (model, userPrompt, responseMessageId, _chatId) => {
const responseMessage = history.messages[responseMessageId];
const docs = messages
.filter((message) => message?.files ?? null)
.map((message) =>
message.files.filter((item) => item.type === 'doc' || item.type === 'collection')
)
.flat(1);
console.log(docs);
scrollToBottom();
try {
const [res, controller] = await generateOpenAIChatCompletion(
localStorage.token,
{
model: model.id,
stream: true,
messages: [
$settings.system || (responseMessage?.userContext ?? null)
? {
role: 'system',
content: `${$settings?.system ?? ''}${
responseMessage?.userContext ?? null
? `\n\nUser Context:\n${(responseMessage?.userContext ?? []).join('\n')}`
: ''
}`
}
: undefined,
...messages
]
.filter((message) => message)
.filter((message) => message.content != '')
.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();
scrollToBottom();
if (res && res.ok && res.body) {
const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks);
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');
}
break;
}
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 {
await handleOpenAIError(null, res, model, responseMessage);
}
} catch (error) {
await handleOpenAIError(error, null, model, responseMessage);
}
messages = messages;
stopResponseFlag = false;
await tick();
if (autoScroll) {
scrollToBottom();
}
if (messages.length == 2) {
window.history.replaceState(history.state, '', `/c/${_chatId}`);
const _title = await generateChatTitle(userPrompt);
await setChatTitle(_chatId, _title);
}
};
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');
};
const regenerateResponse = async (message) => {
console.log('regenerateResponse');
if (messages.length != 0) {
let userMessage = history.messages[message.parentId];
let userPrompt = userMessage.content;
if ((userMessage?.models ?? [...selectedModels]).length == 1) {
await sendPrompt(userPrompt, userMessage.id);
} else {
await sendPrompt(userPrompt, userMessage.id, message.model);
}
}
};
const continueGeneration = async () => {
console.log('continueGeneration');
const _chatId = JSON.parse(JSON.stringify($chatId));
if (messages.length != 0 && messages.at(-1).done == true) {
const responseMessage = history.messages[history.currentId];
responseMessage.done = false;
await tick();
const model = $models.filter((m) => m.id === responseMessage.model).at(0);
if (model) {
if (model?.external) {
await sendPromptOpenAI(
model,
history.messages[responseMessage.parentId].content,
responseMessage.id,
_chatId
);
} else
await sendPromptOllama(
model,
history.messages[responseMessage.parentId].content,
responseMessage.id,
_chatId
);
}
} else {
toast.error($i18n.t(`Model {{modelId}} not found`, { modelId }));
}
};
const generateChatTitle = async (userPrompt) => {
if ($settings?.title?.auto ?? true) {
const model = $models.find((model) => model.id === selectedModels[0]);
const titleModelId =
model?.external ?? false
? $settings?.title?.modelExternal ?? selectedModels[0]
: $settings?.title?.model ?? selectedModels[0];
const titleModel = $models.find((model) => model.id === titleModelId);
console.log(titleModel);
const title = await generateTitle(
localStorage.token,
$settings?.title?.prompt ??
$i18n.t(
"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':"
) + ' {{prompt}}',
titleModelId,
userPrompt,
titleModel?.external ?? false
? titleModel?.source?.toLowerCase() === 'litellm'
? `${LITELLM_API_BASE_URL}/v1`
: `${OPENAI_API_BASE_URL}`
: `${OLLAMA_API_BASE_URL}/v1`
);
return title;
} else {
return `${userPrompt}`;
}
};
const setChatTitle = async (_chatId, _title) => {
if (_chatId === $chatId) {
title = _title;
}
if ($settings.saveChatHistory ?? true) {
chat = await updateChatById(localStorage.token, _chatId, { title: _title });
await chats.set(await getChatList(localStorage.token));
}
};
const getTags = async () => {
return await getTagsById(localStorage.token, $chatId).catch(async (error) => {
return [];
});
};
const addTag = async (tagName) => {
const res = await addTagById(localStorage.token, $chatId, tagName);
tags = await getTags();
chat = await updateChatById(localStorage.token, $chatId, {
tags: tags
});
_tags.set(await getAllChatTags(localStorage.token));
};
const deleteTag = async (tagName) => {
const res = await deleteTagById(localStorage.token, $chatId, tagName);
tags = await getTags();
chat = await updateChatById(localStorage.token, $chatId, {
tags: tags
});
_tags.set(await getAllChatTags(localStorage.token));
};
onMount(async () => {
if (!($settings.saveChatHistory ?? true)) {
await goto('/');
}
});
</script>
<svelte:head>
<title>
{title
? `${title.length > 30 ? `${title.slice(0, 30)}...` : title} | ${$WEBUI_NAME}`
: `${$WEBUI_NAME}`}
</title>
</svelte:head>
{#if loaded}
<div
class="min-h-screen max-h-screen {$showSidebar
? 'md:max-w-[calc(100%-260px)]'
: ''} w-full max-w-full flex flex-col"
>
<Navbar
{title}
{chat}
bind:selectedModels
bind:showModelSelector
shareEnabled={messages.length > 0}
initNewChat={async () => {
if (currentRequestId !== null) {
await cancelOllamaRequest(localStorage.token, currentRequestId);
currentRequestId = null;
}
goto('/');
}}
/>
<div class="flex flex-col flex-auto">
<div
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full"
id="messages-container"
bind:this={messagesContainerElement}
on:scroll={(e) => {
autoScroll =
messagesContainerElement.scrollHeight - messagesContainerElement.scrollTop <=
messagesContainerElement.clientHeight + 5;
}}
>
<div class=" h-full w-full flex flex-col py-4">
<Messages
chatId={$chatId}
{selectedModels}
{selectedModelfiles}
{processing}
bind:history
bind:messages
bind:autoScroll
bind:prompt
bottomPadding={files.length > 0}
{sendPrompt}
{continueGeneration}
{regenerateResponse}
/>
</div>
</div>
</div>
</div>
<MessageInput
bind:files
bind:prompt
bind:autoScroll
bind:selectedModel={atSelectedModel}
{messages}
{submitPrompt}
{stopResponse}
/>
{/if}
<Chat chatIdProp={$page.params.id} />
......@@ -39,10 +39,10 @@
class="flex scrollbar-none overflow-x-auto w-fit text-center text-sm font-medium rounded-xl bg-transparent/10 p-1"
>
<a
class="min-w-fit rounded-lg p-1.5 px-3 {$page.url.pathname.includes('/workspace/modelfiles')
class="min-w-fit rounded-lg p-1.5 px-3 {$page.url.pathname.includes('/workspace/models')
? 'bg-gray-50 dark:bg-gray-850'
: ''} transition"
href="/workspace/modelfiles">{$i18n.t('Modelfiles')}</a
href="/workspace/models">{$i18n.t('Models')}</a
>
<a
......
......@@ -3,6 +3,6 @@
import { onMount } from 'svelte';
onMount(() => {
goto('/workspace/modelfiles');
goto('/workspace/models');
});
</script>
<script>
import Modelfiles from '$lib/components/workspace/Modelfiles.svelte';
</script>
<Modelfiles />
<script>
import { v4 as uuidv4 } from 'uuid';
import { toast } from 'svelte-sonner';
import { goto } from '$app/navigation';
import { settings, user, config, modelfiles, models } from '$lib/stores';
import AdvancedParams from '$lib/components/chat/Settings/Advanced/AdvancedParams.svelte';
import { splitStream } from '$lib/utils';
import { onMount, tick, getContext } from 'svelte';
import { createModel } from '$lib/apis/ollama';
import { createNewModelfile, getModelfileByTagName, getModelfiles } from '$lib/apis/modelfiles';
const i18n = getContext('i18n');
let loading = false;
let filesInputElement;
let inputFiles;
let imageUrl = null;
let digest = '';
let pullProgress = null;
let success = false;
// ///////////
// Modelfile
// ///////////
let title = '';
let tagName = '';
let desc = '';
let raw = true;
let advanced = false;
// Raw Mode
let content = '';
// Builder Mode
let model = '';
let system = '';
let template = '';
let options = {
// Advanced
seed: 0,
stop: '',
temperature: '',
repeat_penalty: '',
repeat_last_n: '',
mirostat: '',
mirostat_eta: '',
mirostat_tau: '',
top_k: '',
top_p: '',
tfs_z: '',
num_ctx: '',
num_predict: ''
};
let modelfileCreator = null;
$: tagName = title !== '' ? `${title.replace(/\s+/g, '-').toLowerCase()}:latest` : '';
$: if (!raw) {
content = `FROM ${model}
${template !== '' ? `TEMPLATE """${template}"""` : ''}
${options.seed !== 0 ? `PARAMETER seed ${options.seed}` : ''}
${options.stop !== '' ? `PARAMETER stop ${options.stop}` : ''}
${options.temperature !== '' ? `PARAMETER temperature ${options.temperature}` : ''}
${options.repeat_penalty !== '' ? `PARAMETER repeat_penalty ${options.repeat_penalty}` : ''}
${options.repeat_last_n !== '' ? `PARAMETER repeat_last_n ${options.repeat_last_n}` : ''}
${options.mirostat !== '' ? `PARAMETER mirostat ${options.mirostat}` : ''}
${options.mirostat_eta !== '' ? `PARAMETER mirostat_eta ${options.mirostat_eta}` : ''}
${options.mirostat_tau !== '' ? `PARAMETER mirostat_tau ${options.mirostat_tau}` : ''}
${options.top_k !== '' ? `PARAMETER top_k ${options.top_k}` : ''}
${options.top_p !== '' ? `PARAMETER top_p ${options.top_p}` : ''}
${options.tfs_z !== '' ? `PARAMETER tfs_z ${options.tfs_z}` : ''}
${options.num_ctx !== '' ? `PARAMETER num_ctx ${options.num_ctx}` : ''}
${options.num_predict !== '' ? `PARAMETER num_predict ${options.num_predict}` : ''}
SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
}
let suggestions = [
{
content: ''
}
];
let categories = {
character: false,
assistant: false,
writing: false,
productivity: false,
programming: false,
'data analysis': false,
lifestyle: false,
education: false,
business: false
};
const saveModelfile = async (modelfile) => {
await createNewModelfile(localStorage.token, modelfile);
await modelfiles.set(await getModelfiles(localStorage.token));
};
const submitHandler = async () => {
loading = true;
if (Object.keys(categories).filter((category) => categories[category]).length == 0) {
toast.error(
'Uh-oh! It looks like you missed selecting a category. Please choose one to complete your modelfile.'
);
loading = false;
success = false;
return success;
}
if (
$models.map((model) => model.name).includes(tagName) ||
(await getModelfileByTagName(localStorage.token, tagName).catch(() => false))
) {
toast.error(
`Uh-oh! It looks like you already have a model named '${tagName}'. Please choose a different name to complete your modelfile.`
);
loading = false;
success = false;
return success;
}
if (
title !== '' &&
desc !== '' &&
content !== '' &&
Object.keys(categories).filter((category) => categories[category]).length > 0 &&
!$models.includes(tagName)
) {
const res = await createModel(localStorage.token, tagName, content);
if (res) {
const reader = res.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(splitStream('\n'))
.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) break;
try {
let lines = value.split('\n');
for (const line of lines) {
if (line !== '') {
console.log(line);
let data = JSON.parse(line);
console.log(data);
if (data.error) {
throw data.error;
}
if (data.detail) {
throw data.detail;
}
if (data.status) {
if (
!data.digest &&
!data.status.includes('writing') &&
!data.status.includes('sha256')
) {
toast.success(data.status);
if (data.status === 'success') {
success = true;
}
} else {
if (data.digest) {
digest = data.digest;
if (data.completed) {
pullProgress = Math.round((data.completed / data.total) * 1000) / 10;
} else {
pullProgress = 100;
}
}
}
}
}
}
} catch (error) {
console.log(error);
toast.error(error);
}
}
}
if (success) {
await saveModelfile({
tagName: tagName,
imageUrl: imageUrl,
title: title,
desc: desc,
content: content,
suggestionPrompts: suggestions.filter((prompt) => prompt.content !== ''),
categories: Object.keys(categories).filter((category) => categories[category]),
user: modelfileCreator !== null ? modelfileCreator : undefined
});
await goto('/workspace/modelfiles');
}
}
loading = false;
success = false;
};
onMount(async () => {
window.addEventListener('message', async (event) => {
if (
![
'https://ollamahub.com',
'https://www.ollamahub.com',
'https://openwebui.com',
'https://www.openwebui.com',
'http://localhost:5173'
].includes(event.origin)
)
return;
const modelfile = JSON.parse(event.data);
console.log(modelfile);
imageUrl = modelfile.imageUrl;
title = modelfile.title;
await tick();
tagName = `${modelfile.user.username === 'hub' ? '' : `hub/`}${modelfile.user.username}/${
modelfile.tagName
}`;
desc = modelfile.desc;
content = modelfile.content;
suggestions =
modelfile.suggestionPrompts.length != 0
? modelfile.suggestionPrompts
: [
{
content: ''
}
];
modelfileCreator = {
username: modelfile.user.username,
name: modelfile.user.name
};
for (const category of modelfile.categories) {
categories[category.toLowerCase()] = true;
}
});
if (window.opener ?? false) {
window.opener.postMessage('loaded', '*');
}
if (sessionStorage.modelfile) {
const modelfile = JSON.parse(sessionStorage.modelfile);
console.log(modelfile);
imageUrl = modelfile.imageUrl;
title = modelfile.title;
await tick();
tagName = modelfile.tagName;
desc = modelfile.desc;
content = modelfile.content;
suggestions =
modelfile.suggestionPrompts.length != 0
? modelfile.suggestionPrompts
: [
{
content: ''
}
];
for (const category of modelfile.categories) {
categories[category.toLowerCase()] = true;
}
sessionStorage.removeItem('modelfile');
}
});
</script>
<div class="w-full max-h-full">
<input
bind:this={filesInputElement}
bind:files={inputFiles}
type="file"
hidden
accept="image/*"
on:change={() => {
let reader = new FileReader();
reader.onload = (event) => {
let originalImageUrl = `${event.target.result}`;
const img = new Image();
img.src = originalImageUrl;
img.onload = function () {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Calculate the aspect ratio of the image
const aspectRatio = img.width / img.height;
// Calculate the new width and height to fit within 100x100
let newWidth, newHeight;
if (aspectRatio > 1) {
newWidth = 100 * aspectRatio;
newHeight = 100;
} else {
newWidth = 100;
newHeight = 100 / aspectRatio;
}
// Set the canvas size
canvas.width = 100;
canvas.height = 100;
// Calculate the position to center the image
const offsetX = (100 - newWidth) / 2;
const offsetY = (100 - newHeight) / 2;
// Draw the image on the canvas
ctx.drawImage(img, offsetX, offsetY, newWidth, newHeight);
// Get the base64 representation of the compressed image
const compressedSrc = canvas.toDataURL('image/jpeg');
// Display the compressed image
imageUrl = compressedSrc;
inputFiles = null;
};
};
if (
inputFiles &&
inputFiles.length > 0 &&
['image/gif', 'image/webp', 'image/jpeg', 'image/png'].includes(inputFiles[0]['type'])
) {
reader.readAsDataURL(inputFiles[0]);
} else {
console.log(`Unsupported File Type '${inputFiles[0]['type']}'.`);
inputFiles = null;
}
}}
/>
<button
class="flex space-x-1"
on:click={() => {
history.back();
}}
>
<div class=" self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-4 h-4"
>
<path
fill-rule="evenodd"
d="M17 10a.75.75 0 01-.75.75H5.612l4.158 3.96a.75.75 0 11-1.04 1.08l-5.5-5.25a.75.75 0 010-1.08l5.5-5.25a.75.75 0 111.04 1.08L5.612 9.25H16.25A.75.75 0 0117 10z"
clip-rule="evenodd"
/>
</svg>
</div>
<div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div>
</button>
<!-- <hr class="my-3 dark:border-gray-700" /> -->
<form
class="flex flex-col max-w-2xl mx-auto mt-4 mb-10"
on:submit|preventDefault={() => {
submitHandler();
}}
>
<div class="flex justify-center my-4">
<div class="self-center">
<button
class=" {imageUrl
? ''
: 'p-6'} rounded-full dark:bg-gray-700 border border-dashed border-gray-200"
type="button"
on:click={() => {
filesInputElement.click();
}}
>
{#if imageUrl}
<img
src={imageUrl}
alt="modelfile profile"
class=" rounded-full w-20 h-20 object-cover"
/>
{:else}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-8"
>
<path
fill-rule="evenodd"
d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z"
clip-rule="evenodd"
/>
</svg>
{/if}
</button>
</div>
</div>
<div class="my-2 flex space-x-2">
<div class="flex-1">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Name')}*</div>
<div>
<input
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
placeholder={$i18n.t('Name your modelfile')}
bind:value={title}
required
/>
</div>
</div>
<div class="flex-1">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Model Tag Name')}*</div>
<div>
<input
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
placeholder={$i18n.t('Add a model tag name')}
bind:value={tagName}
required
/>
</div>
</div>
</div>
<div class="my-2">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Description')}*</div>
<div>
<input
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
placeholder={$i18n.t('Add a short description about what this modelfile does')}
bind:value={desc}
required
/>
</div>
</div>
<div class="my-2">
<div class="flex w-full justify-between">
<div class=" self-center text-sm font-semibold">{$i18n.t('Modelfile')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
raw = !raw;
}}
>
{#if raw}
<span class="ml-2 self-center"> {$i18n.t('Raw Format')} </span>
{:else}
<span class="ml-2 self-center"> {$i18n.t('Builder Mode')} </span>
{/if}
</button>
</div>
<!-- <div class=" text-sm font-semibold mb-2"></div> -->
{#if raw}
<div class="mt-2">
<div class=" text-xs font-semibold mb-2">{$i18n.t('Content')}*</div>
<div>
<textarea
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
placeholder={`FROM llama2\nPARAMETER temperature 1\nSYSTEM """\nYou are Mario from Super Mario Bros, acting as an assistant.\n"""`}
rows="6"
bind:value={content}
required
/>
</div>
<div class="text-xs text-gray-400 dark:text-gray-500">
{$i18n.t('Not sure what to write? Switch to')}
<button
class="text-gray-500 dark:text-gray-300 font-medium cursor-pointer"
type="button"
on:click={() => {
raw = !raw;
}}>{$i18n.t('Builder Mode')}</button
>
or
<a
class=" text-gray-500 dark:text-gray-300 font-medium"
href="https://openwebui.com"
target="_blank"
>
{$i18n.t('Click here to check other modelfiles.')}
</a>
</div>
</div>
{:else}
<div class="my-2">
<div class=" text-xs font-semibold mb-2">{$i18n.t('From (Base Model)')}*</div>
<div>
<input
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
placeholder="Write a modelfile base model name (e.g. llama2, mistral)"
bind:value={model}
required
/>
</div>
<div class="mt-1 text-xs text-gray-400 dark:text-gray-500">
{$i18n.t('To access the available model names for downloading,')}
<a
class=" text-gray-500 dark:text-gray-300 font-medium"
href="https://ollama.com/library"
target="_blank">{$i18n.t('click here.')}</a
>
</div>
</div>
<div class="my-1">
<div class=" text-xs font-semibold mb-2">{$i18n.t('System Prompt')}</div>
<div>
<textarea
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg -mb-1"
placeholder={`Write your modelfile system prompt content here\ne.g.) You are Mario from Super Mario Bros, acting as an assistant.`}
rows="4"
bind:value={system}
/>
</div>
</div>
<div class="flex w-full justify-between">
<div class=" self-center text-sm font-semibold">
{$i18n.t('Modelfile Advanced Settings')}
</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
advanced = !advanced;
}}
>
{#if advanced}
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{/if}
</button>
</div>
{#if advanced}
<div class="my-2">
<div class=" text-xs font-semibold mb-2">{$i18n.t('Template')}</div>
<div>
<textarea
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg -mb-1"
placeholder="Write your modelfile template content here"
rows="4"
bind:value={template}
/>
</div>
</div>
<div class="my-2">
<div class=" text-xs font-semibold mb-2">{$i18n.t('Parameters')}</div>
<div>
<AdvancedParams bind:options />
</div>
</div>
{/if}
{/if}
</div>
<div class="my-2">
<div class="flex w-full justify-between mb-2">
<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt suggestions')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
if (suggestions.length === 0 || suggestions.at(-1).content !== '') {
suggestions = [...suggestions, { content: '' }];
}
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z"
/>
</svg>
</button>
</div>
<div class="flex flex-col space-y-1">
{#each suggestions as prompt, promptIdx}
<div class=" flex border dark:border-gray-600 rounded-lg">
<input
class="px-3 py-1.5 text-sm w-full bg-transparent outline-none border-r dark:border-gray-600"
placeholder={$i18n.t('Write a prompt suggestion (e.g. Who are you?)')}
bind:value={prompt.content}
/>
<button
class="px-2"
type="button"
on:click={() => {
suggestions.splice(promptIdx, 1);
suggestions = suggestions;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
/>
</svg>
</button>
</div>
{/each}
</div>
</div>
<div class="my-2">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Categories')}</div>
<div class="grid grid-cols-4">
{#each Object.keys(categories) as category}
<div class="flex space-x-2 text-sm">
<input type="checkbox" bind:checked={categories[category]} />
<div class="capitalize">{category}</div>
</div>
{/each}
</div>
</div>
{#if pullProgress !== null}
<div class="my-2">
<div class=" text-sm font-semibold mb-2">{$i18n.t('Pull Progress')}</div>
<div class="w-full rounded-full dark:bg-gray-800">
<div
class="dark:bg-gray-600 bg-gray-500 text-xs font-medium text-gray-100 text-center p-0.5 leading-none rounded-full"
style="width: {Math.max(15, pullProgress ?? 0)}%"
>
{pullProgress ?? 0}%
</div>
</div>
<div class="mt-1 text-xs dark:text-gray-500" style="font-size: 0.5rem;">
{digest}
</div>
</div>
{/if}
<div class="my-2 flex justify-end">
<button
class=" text-sm px-3 py-2 transition rounded-xl {loading
? ' cursor-not-allowed bg-gray-100 dark:bg-gray-800'
: ' bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-800'} flex"
type="submit"
disabled={loading}
>
<div class=" self-center font-medium">{$i18n.t('Save & Create')}</div>
{#if loading}
<div class="ml-1.5 self-center">
<svg
class=" w-4 h-4"
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
><style>
.spinner_ajPY {
transform-origin: center;
animation: spinner_AtaB 0.75s infinite linear;
}
@keyframes spinner_AtaB {
100% {
transform: rotate(360deg);
}
}
</style><path
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
opacity=".25"
/><path
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
class="spinner_ajPY"
/></svg
>
</div>
{/if}
</button>
</div>
</form>
</div>
<script>
import Models from '$lib/components/workspace/Models.svelte';
</script>
<Models />
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment