Unverified Commit b8d7fdf1 authored by Timothy Jaeryang Baek's avatar Timothy Jaeryang Baek Committed by GitHub
Browse files

Merge pull request #1965 from open-webui/dev

0.1.124
parents 30b05311 b44ae536
<script lang="ts">
import { getDocs } from '$lib/apis/documents';
import {
getRAGConfig,
updateRAGConfig,
getQuerySettings,
scanDocs,
updateQuerySettings,
resetVectorDB,
getEmbeddingConfig,
updateEmbeddingConfig,
getRerankingConfig,
updateRerankingConfig
} from '$lib/apis/rag';
import { documents, models } from '$lib/stores';
import { onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner';
import Tooltip from '$lib/components/common/Tooltip.svelte';
const i18n = getContext('i18n');
export let saveHandler: Function;
let scanDirLoading = false;
let updateEmbeddingModelLoading = false;
let updateRerankingModelLoading = false;
let showResetConfirm = false;
let chunkSize = 0;
let chunkOverlap = 0;
let pdfExtractImages = true;
const submitHandler = async () => {
const res = await updateRAGConfig(localStorage.token, {
pdf_extract_images: pdfExtractImages,
chunk: {
chunk_overlap: chunkOverlap,
chunk_size: chunkSize
}
});
};
onMount(async () => {
const res = await getRAGConfig(localStorage.token);
if (res) {
pdfExtractImages = res.pdf_extract_images;
chunkSize = res.chunk.chunk_size;
chunkOverlap = res.chunk.chunk_overlap;
}
});
</script>
<form
class="flex flex-col h-full justify-between space-y-3 text-sm"
on:submit|preventDefault={() => {
submitHandler();
saveHandler();
}}
>
<div class=" space-y-3 pr-1.5 overflow-y-scroll h-full max-h-[22rem]">
<div class=" ">
<div class=" text-sm font-medium">{$i18n.t('Chunk Params')}</div>
<div class=" flex">
<div class=" flex w-full justify-between">
<div class="self-center text-xs font-medium min-w-fit">{$i18n.t('Chunk Size')}</div>
<div class="self-center p-3">
<input
class=" w-full rounded-lg py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="number"
placeholder={$i18n.t('Enter Chunk Size')}
bind:value={chunkSize}
autocomplete="off"
min="0"
/>
</div>
</div>
<div class="flex w-full">
<div class=" self-center text-xs font-medium min-w-fit">
{$i18n.t('Chunk Overlap')}
</div>
<div class="self-center p-3">
<input
class="w-full rounded-lg py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="number"
placeholder={$i18n.t('Enter Chunk Overlap')}
bind:value={chunkOverlap}
autocomplete="off"
min="0"
/>
</div>
</div>
</div>
<div class="pr-2">
<div class="flex justify-between items-center text-xs">
<div class=" text-xs font-medium">{$i18n.t('PDF Extract Images (OCR)')}</div>
<button
class=" text-xs font-medium text-gray-500"
type="button"
on:click={() => {
pdfExtractImages = !pdfExtractImages;
}}>{pdfExtractImages ? $i18n.t('On') : $i18n.t('Off')}</button
>
</div>
</div>
</div>
</div>
<div class="flex justify-end pt-3 text-sm font-medium">
<button
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
type="submit"
>
{$i18n.t('Save')}
</button>
</div>
</form>
<script lang="ts">
import { getDocs } from '$lib/apis/documents';
import {
getRAGConfig,
updateRAGConfig,
getQuerySettings,
scanDocs,
updateQuerySettings,
resetVectorDB,
getEmbeddingConfig,
updateEmbeddingConfig,
getRerankingConfig,
updateRerankingConfig
} from '$lib/apis/rag';
import { documents, models } from '$lib/stores';
import { onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner';
import Tooltip from '$lib/components/common/Tooltip.svelte';
const i18n = getContext('i18n');
export let saveHandler: Function;
let querySettings = {
template: '',
r: 0.0,
k: 4,
hybrid: false
};
const submitHandler = async () => {
querySettings = await updateQuerySettings(localStorage.token, querySettings);
};
onMount(async () => {
querySettings = await getQuerySettings(localStorage.token);
});
</script>
<form
class="flex flex-col h-full justify-between space-y-3 text-sm"
on:submit|preventDefault={() => {
submitHandler();
saveHandler();
}}
>
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[22rem]">
<div class=" ">
<div class=" text-sm font-medium">{$i18n.t('Query Params')}</div>
<div class=" flex">
<div class=" flex w-full justify-between">
<div class="self-center text-xs font-medium min-w-fit">{$i18n.t('Top K')}</div>
<div class="self-center p-3">
<input
class=" w-full rounded-lg py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="number"
placeholder={$i18n.t('Enter Top K')}
bind:value={querySettings.k}
autocomplete="off"
min="0"
/>
</div>
</div>
{#if querySettings.hybrid === true}
<div class="flex w-full">
<div class=" self-center text-xs font-medium min-w-fit">
{$i18n.t('Minimum Score')}
</div>
<div class="self-center p-3">
<input
class=" w-full rounded-lg py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="number"
step="0.01"
placeholder={$i18n.t('Enter Score')}
bind:value={querySettings.r}
autocomplete="off"
min="0.0"
title={$i18n.t('The score should be a value between 0.0 (0%) and 1.0 (100%).')}
/>
</div>
</div>
{/if}
</div>
{#if querySettings.hybrid === true}
<div class="mt-2 mb-1 text-xs text-gray-400 dark:text-gray-500">
{$i18n.t(
'Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.'
)}
</div>
<hr class=" dark:border-gray-700 my-3" />
{/if}
<div>
<div class=" mb-2.5 text-sm font-medium">{$i18n.t('RAG Template')}</div>
<textarea
bind:value={querySettings.template}
class="w-full rounded-lg px-4 py-3 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none resize-none"
rows="4"
/>
</div>
</div>
</div>
<div class="flex justify-end pt-3 text-sm font-medium">
<button
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
type="submit"
>
{$i18n.t('Save')}
</button>
</div>
</form>
<script lang="ts">
import { getRAGConfig, updateRAGConfig } from '$lib/apis/rag';
import { documents, models } from '$lib/stores';
import { onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner';
const i18n = getContext('i18n');
export let saveHandler: Function;
let webLoaderSSLVerification = true;
let youtubeLanguage = 'en';
let youtubeTranslation = null;
const submitHandler = async () => {
const res = await updateRAGConfig(localStorage.token, {
web_loader_ssl_verification: webLoaderSSLVerification,
youtube: {
language: youtubeLanguage.split(',').map((lang) => lang.trim()),
translation: youtubeTranslation
}
});
};
onMount(async () => {
const res = await getRAGConfig(localStorage.token);
if (res) {
webLoaderSSLVerification = res.web_loader_ssl_verification;
youtubeLanguage = res.youtube.language.join(',');
youtubeTranslation = res.youtube.translation;
}
});
</script>
<form
class="flex flex-col h-full justify-between space-y-3 text-sm"
on:submit|preventDefault={() => {
submitHandler();
saveHandler();
}}
>
<div class=" space-y-3 pr-1.5 overflow-y-scroll h-full max-h-[22rem]">
<div>
<div class=" mb-1 text-sm font-medium">
{$i18n.t('Web Loader Settings')}
</div>
<div>
<div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">
{$i18n.t('Bypass SSL verification for Websites')}
</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
on:click={() => {
webLoaderSSLVerification = !webLoaderSSLVerification;
submitHandler();
}}
type="button"
>
{#if webLoaderSSLVerification === true}
<span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if}
</button>
</div>
</div>
<div class=" mt-2 mb-1 text-sm font-medium">
{$i18n.t('Youtube Loader Settings')}
</div>
<div>
<div class=" py-0.5 flex w-full justify-between">
<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Language')}</div>
<div class=" flex-1 self-center">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="text"
placeholder={$i18n.t('Enter language codes')}
bind:value={youtubeLanguage}
autocomplete="off"
/>
</div>
</div>
</div>
</div>
</div>
<div class="flex justify-end pt-3 text-sm font-medium">
<button
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
type="submit"
>
{$i18n.t('Save')}
</button>
</div>
</form>
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
import { getContext } from 'svelte'; import { getContext } from 'svelte';
import Modal from '../common/Modal.svelte'; import Modal from '../common/Modal.svelte';
import General from './Settings/General.svelte'; import General from './Settings/General.svelte';
import ChunkParams from './Settings/ChunkParams.svelte';
import QueryParams from './Settings/QueryParams.svelte';
import WebParams from './Settings/WebParams.svelte';
import { toast } from 'svelte-sonner';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
...@@ -62,25 +66,115 @@ ...@@ -62,25 +66,115 @@
</div> </div>
<div class=" self-center">{$i18n.t('General')}</div> <div class=" self-center">{$i18n.t('General')}</div>
</button> </button>
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'chunk'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
on:click={() => {
selectedTab = 'chunk';
}}
>
<div class=" self-center mr-2">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-4 h-4"
>
<path
fill-rule="evenodd"
d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875ZM12.75 12a.75.75 0 0 0-1.5 0v2.25H9a.75.75 0 0 0 0 1.5h2.25V18a.75.75 0 0 0 1.5 0v-2.25H15a.75.75 0 0 0 0-1.5h-2.25V12Z"
clip-rule="evenodd"
/>
<path
d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z"
/>
</svg>
</div>
<div class=" self-center">{$i18n.t('Chunk Params')}</div>
</button>
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'query'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
on:click={() => {
selectedTab = 'query';
}}
>
<div class=" self-center mr-2">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-4 h-4"
>
<path d="M11.625 16.5a1.875 1.875 0 1 0 0-3.75 1.875 1.875 0 0 0 0 3.75Z" />
<path
fill-rule="evenodd"
d="M5.625 1.5H9a3.75 3.75 0 0 1 3.75 3.75v1.875c0 1.036.84 1.875 1.875 1.875H16.5a3.75 3.75 0 0 1 3.75 3.75v7.875c0 1.035-.84 1.875-1.875 1.875H5.625a1.875 1.875 0 0 1-1.875-1.875V3.375c0-1.036.84-1.875 1.875-1.875Zm6 16.5c.66 0 1.277-.19 1.797-.518l1.048 1.048a.75.75 0 0 0 1.06-1.06l-1.047-1.048A3.375 3.375 0 1 0 11.625 18Z"
clip-rule="evenodd"
/>
<path
d="M14.25 5.25a5.23 5.23 0 0 0-1.279-3.434 9.768 9.768 0 0 1 6.963 6.963A5.23 5.23 0 0 0 16.5 7.5h-1.875a.375.375 0 0 1-.375-.375V5.25Z"
/>
</svg>
</div>
<div class=" self-center">{$i18n.t('Query Params')}</div>
</button>
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'web'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
on:click={() => {
selectedTab = 'web';
}}
>
<div class=" self-center mr-2">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M21.721 12.752a9.711 9.711 0 0 0-.945-5.003 12.754 12.754 0 0 1-4.339 2.708 18.991 18.991 0 0 1-.214 4.772 17.165 17.165 0 0 0 5.498-2.477ZM14.634 15.55a17.324 17.324 0 0 0 .332-4.647c-.952.227-1.945.347-2.966.347-1.021 0-2.014-.12-2.966-.347a17.515 17.515 0 0 0 .332 4.647 17.385 17.385 0 0 0 5.268 0ZM9.772 17.119a18.963 18.963 0 0 0 4.456 0A17.182 17.182 0 0 1 12 21.724a17.18 17.18 0 0 1-2.228-4.605ZM7.777 15.23a18.87 18.87 0 0 1-.214-4.774 12.753 12.753 0 0 1-4.34-2.708 9.711 9.711 0 0 0-.944 5.004 17.165 17.165 0 0 0 5.498 2.477ZM21.356 14.752a9.765 9.765 0 0 1-7.478 6.817 18.64 18.64 0 0 0 1.988-4.718 18.627 18.627 0 0 0 5.49-2.098ZM2.644 14.752c1.682.971 3.53 1.688 5.49 2.099a18.64 18.64 0 0 0 1.988 4.718 9.765 9.765 0 0 1-7.478-6.816ZM13.878 2.43a9.755 9.755 0 0 1 6.116 3.986 11.267 11.267 0 0 1-3.746 2.504 18.63 18.63 0 0 0-2.37-6.49ZM12 2.276a17.152 17.152 0 0 1 2.805 7.121c-.897.23-1.837.353-2.805.353-.968 0-1.908-.122-2.805-.353A17.151 17.151 0 0 1 12 2.276ZM10.122 2.43a18.629 18.629 0 0 0-2.37 6.49 11.266 11.266 0 0 1-3.746-2.504 9.754 9.754 0 0 1 6.116-3.985Z"
/>
</svg>
</div>
<div class=" self-center">{$i18n.t('Web Params')}</div>
</button>
</div> </div>
<div class="flex-1 md:min-h-[380px]"> <div class="flex-1 md:min-h-[380px]">
{#if selectedTab === 'general'} {#if selectedTab === 'general'}
<General <General
saveHandler={() => { saveHandler={() => {
show = false; toast.success($i18n.t('Settings saved successfully!'));
}}
/>
{:else if selectedTab === 'chunk'}
<ChunkParams
saveHandler={() => {
toast.success($i18n.t('Settings saved successfully!'));
}} }}
/> />
<!-- <General {:else if selectedTab === 'query'}
<QueryParams
saveHandler={() => { saveHandler={() => {
show = false; toast.success($i18n.t('Settings saved successfully!'));
}} }}
/> --> />
<!-- {:else if selectedTab === 'users'} {:else if selectedTab === 'web'}
<Users <WebParams
saveHandler={() => { saveHandler={() => {
show = false; toast.success($i18n.t('Settings saved successfully!'));
}} }}
/> --> />
{/if} {/if}
</div> </div>
</div> </div>
......
...@@ -44,6 +44,28 @@ ...@@ -44,6 +44,28 @@
let showDropdown = false; let showDropdown = false;
let isEditing = false; let isEditing = false;
let filteredChatList = [];
$: filteredChatList = $chats.filter((chat) => {
if (search === '') {
return true;
} else {
let title = chat.title.toLowerCase();
const query = search.toLowerCase();
let contentMatches = false;
// Access the messages within chat.chat.messages
if (chat.chat && chat.chat.messages && Array.isArray(chat.chat.messages)) {
contentMatches = chat.chat.messages.some((message) => {
// Check if message.content exists and includes the search query
return message.content && message.content.toLowerCase().includes(query);
});
}
return title.includes(query) || contentMatches;
}
});
onMount(async () => { onMount(async () => {
showSidebar.set(window.innerWidth > BREAKPOINT); showSidebar.set(window.innerWidth > BREAKPOINT);
await chats.set(await getChatList(localStorage.token)); await chats.set(await getChatList(localStorage.token));
...@@ -112,7 +134,7 @@ ...@@ -112,7 +134,7 @@
const editChatTitle = async (id, _title) => { const editChatTitle = async (id, _title) => {
if (_title === '') { if (_title === '') {
toast.error('Title cannot be an empty string.'); toast.error($i18n.t('Title cannot be an empty string.'));
} else { } else {
title = _title; title = _title;
...@@ -397,7 +419,7 @@ ...@@ -397,7 +419,7 @@
await chats.set(await getChatList(localStorage.token)); await chats.set(await getChatList(localStorage.token));
}} }}
> >
all {$i18n.t('all')}
</button> </button>
{#each $tags as tag} {#each $tags as tag}
<button <button
...@@ -418,25 +440,35 @@ ...@@ -418,25 +440,35 @@
{/if} {/if}
<div class="pl-2 my-2 flex-1 flex flex-col space-y-1 overflow-y-auto scrollbar-none"> <div class="pl-2 my-2 flex-1 flex flex-col space-y-1 overflow-y-auto scrollbar-none">
{#each $chats.filter((chat) => { {#each filteredChatList as chat, idx}
if (search === '') { {#if idx === 0 || (idx > 0 && chat.time_range !== filteredChatList[idx - 1].time_range)}
return true; <div
} else { class="w-full pl-2.5 text-xs text-gray-500 dark:text-gray-500 font-medium {idx === 0
let title = chat.title.toLowerCase(); ? ''
const query = search.toLowerCase(); : 'pt-5'} pb-0.5"
>
let contentMatches = false; {$i18n.t(chat.time_range)}
// Access the messages within chat.chat.messages <!-- localisation keys for time_range to be recognized from the i18next parser (so they don't get automatically removed):
if (chat.chat && chat.chat.messages && Array.isArray(chat.chat.messages)) { {$i18n.t('Today')}
contentMatches = chat.chat.messages.some((message) => { {$i18n.t('Yesterday')}
// Check if message.content exists and includes the search query {$i18n.t('Previous 7 days')}
return message.content && message.content.toLowerCase().includes(query); {$i18n.t('Previous 30 days')}
}); {$i18n.t('January')}
} {$i18n.t('February')}
{$i18n.t('March')}
return title.includes(query) || contentMatches; {$i18n.t('April')}
} {$i18n.t('May')}
}) as chat, i} {$i18n.t('June')}
{$i18n.t('July')}
{$i18n.t('August')}
{$i18n.t('September')}
{$i18n.t('October')}
{$i18n.t('November')}
{$i18n.t('December')}
-->
</div>
{/if}
<div class=" w-full pr-2 relative group"> <div class=" w-full pr-2 relative group">
{#if chatTitleEditId === chat.id} {#if chatTitleEditId === chat.id}
<div <div
...@@ -836,12 +868,12 @@ ...@@ -836,12 +868,12 @@
> >
<div class="flex h-6 w-6 flex-col items-center"> <div class="flex h-6 w-6 flex-col items-center">
<div <div
class="h-3 w-1 rounded-full bg-[#0f0f0f] dark:bg-white rotate-0 translate-y-[0.15rem] {show class="h-3 w-1 rounded-full bg-[#0f0f0f] dark:bg-white rotate-0 translate-y-[0.15rem] {$showSidebar
? 'group-hover:rotate-[15deg]' ? 'group-hover:rotate-[15deg]'
: 'group-hover:rotate-[-15deg]'}" : 'group-hover:rotate-[-15deg]'}"
/> />
<div <div
class="h-3 w-1 rounded-full bg-[#0f0f0f] dark:bg-white rotate-0 translate-y-[-0.15rem] {show class="h-3 w-1 rounded-full bg-[#0f0f0f] dark:bg-white rotate-0 translate-y-[-0.15rem] {$showSidebar
? 'group-hover:rotate-[-15deg]' ? 'group-hover:rotate-[-15deg]'
: 'group-hover:rotate-[15deg]'}" : 'group-hover:rotate-[15deg]'}"
/> />
......
...@@ -161,7 +161,9 @@ ...@@ -161,7 +161,9 @@
{/each} --> {/each} -->
</div> </div>
{:else} {:else}
<div class="text-left text-sm w-full mb-8">You have no archived conversations.</div> <div class="text-left text-sm w-full mb-8">
{$i18n.t('You have no archived conversations.')}
</div>
{/if} {/if}
</div> </div>
</div> </div>
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
}} }}
> >
<Share /> <Share />
<div class="flex items-center">Share</div> <div class="flex items-center">{$i18n.t('Share')}</div>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item <DropdownMenu.Item
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
}} }}
> >
<Pencil strokeWidth="2" /> <Pencil strokeWidth="2" />
<div class="flex items-center">Rename</div> <div class="flex items-center">{$i18n.t('Rename')}</div>
</DropdownMenu.Item> </DropdownMenu.Item>
<DropdownMenu.Item <DropdownMenu.Item
...@@ -69,13 +69,19 @@ ...@@ -69,13 +69,19 @@
}} }}
> >
<GarbageBin strokeWidth="2" /> <GarbageBin strokeWidth="2" />
<div class="flex items-center">Delete</div> <div class="flex items-center">{$i18n.t('Delete')}</div>
</DropdownMenu.Item> </DropdownMenu.Item>
<hr class="border-gray-100 dark:border-gray-800 mt-2.5 mb-1.5" /> <hr class="border-gray-100 dark:border-gray-800 mt-2.5 mb-1.5" />
<div class="flex p-1"> <div class="flex p-1">
<Tags {chatId} /> <Tags
{chatId}
on:close={() => {
show = false;
onClose();
}}
/>
</div> </div>
</DropdownMenu.Content> </DropdownMenu.Content>
</div> </div>
......
This diff is collapsed.
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
"Add a short description about what this modelfile does": "Добавяне на кратко описание за това какво прави този модфайл", "Add a short description about what this modelfile does": "Добавяне на кратко описание за това какво прави този модфайл",
"Add a short title for this prompt": "Добавяне на кратко заглавие за този промпт", "Add a short title for this prompt": "Добавяне на кратко заглавие за този промпт",
"Add a tag": "Добавяне на таг", "Add a tag": "Добавяне на таг",
"Add custom prompt": "",
"Add Docs": "Добавяне на Документи", "Add Docs": "Добавяне на Документи",
"Add Files": "Добавяне на Файлове", "Add Files": "Добавяне на Файлове",
"Add message": "Добавяне на съобщение", "Add message": "Добавяне на съобщение",
...@@ -27,6 +28,7 @@ ...@@ -27,6 +28,7 @@
"Admin Settings": "Настройки на Администратор", "Admin Settings": "Настройки на Администратор",
"Advanced Parameters": "Разширени Параметри", "Advanced Parameters": "Разширени Параметри",
"all": "всички", "all": "всички",
"All Documents": "",
"All Users": "Всички Потребители", "All Users": "Всички Потребители",
"Allow": "Позволи", "Allow": "Позволи",
"Allow Chat Deletion": "Позволи Изтриване на Чат", "Allow Chat Deletion": "Позволи Изтриване на Чат",
...@@ -34,17 +36,21 @@ ...@@ -34,17 +36,21 @@
"Already have an account?": "Вече имате акаунт? ", "Already have an account?": "Вече имате акаунт? ",
"an assistant": "асистент", "an assistant": "асистент",
"and": "и", "and": "и",
"and create a new shared link.": "",
"API Base URL": "API Базов URL", "API Base URL": "API Базов URL",
"API Key": "API Ключ", "API Key": "API Ключ",
"API Key created.": "", "API Key created.": "",
"API keys": "", "API keys": "",
"API RPM": "API RPM", "API RPM": "API RPM",
"April": "",
"Archive": "", "Archive": "",
"Archived Chats": "", "Archived Chats": "",
"are allowed - Activate this command by typing": "са разрешени - Активирайте тази команда чрез въвеждане", "are allowed - Activate this command by typing": "са разрешени - Активирайте тази команда чрез въвеждане",
"Are you sure?": "Сигурни ли сте?", "Are you sure?": "Сигурни ли сте?",
"Attach file": "",
"Attention to detail": "", "Attention to detail": "",
"Audio": "Аудио", "Audio": "Аудио",
"August": "",
"Auto-playback response": "Аувтоматично възпроизвеждане на Отговора", "Auto-playback response": "Аувтоматично възпроизвеждане на Отговора",
"Auto-send input after 3 sec.": "Аувтоматично изпращане на входа след 3 сек.", "Auto-send input after 3 sec.": "Аувтоматично изпращане на входа след 3 сек.",
"AUTOMATIC1111 Base URL": "AUTOMATIC1111 Базов URL", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 Базов URL",
...@@ -52,8 +58,10 @@ ...@@ -52,8 +58,10 @@
"available!": "наличен!", "available!": "наличен!",
"Back": "Назад", "Back": "Назад",
"Bad Response": "", "Bad Response": "",
"before": "",
"Being lazy": "", "Being lazy": "",
"Builder Mode": "Режим на Създаване", "Builder Mode": "Режим на Създаване",
"Bypass SSL verification for Websites": "",
"Cancel": "Отказ", "Cancel": "Отказ",
"Categories": "Категории", "Categories": "Категории",
"Change Password": "Промяна на Парола", "Change Password": "Промяна на Парола",
...@@ -68,7 +76,9 @@ ...@@ -68,7 +76,9 @@
"Chunk Overlap": "Chunk Overlap", "Chunk Overlap": "Chunk Overlap",
"Chunk Params": "Chunk Params", "Chunk Params": "Chunk Params",
"Chunk Size": "Chunk Size", "Chunk Size": "Chunk Size",
"Citation": "",
"Click here for help.": "Натиснете тук за помощ.", "Click here for help.": "Натиснете тук за помощ.",
"Click here to": "",
"Click here to check other modelfiles.": "Натиснете тук за проверка на други моделфайлове.", "Click here to check other modelfiles.": "Натиснете тук за проверка на други моделфайлове.",
"Click here to select": "Натиснете тук, за да изберете", "Click here to select": "Натиснете тук, за да изберете",
"Click here to select a csv file.": "", "Click here to select a csv file.": "",
...@@ -96,6 +106,8 @@ ...@@ -96,6 +106,8 @@
"Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "Създайте кратка фраза от 3-5 думи като заглавие за следващото запитване, като стриктно спазвате ограничението от 3-5 думи и избягвате използването на думата 'заглавие':", "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 modelfile": "Създаване на модфайл",
"Create Account": "Създаване на Акаунт", "Create Account": "Създаване на Акаунт",
"Create new key": "",
"Create new secret key": "",
"Created at": "Създадено на", "Created at": "Създадено на",
"Created At": "", "Created At": "",
"Current Model": "Текущ модел", "Current Model": "Текущ модел",
...@@ -103,8 +115,10 @@ ...@@ -103,8 +115,10 @@
"Custom": "Персонализиран", "Custom": "Персонализиран",
"Customize Ollama models for a specific purpose": "Персонализиране на Ollama моделите за конкретна цел", "Customize Ollama models for a specific purpose": "Персонализиране на Ollama моделите за конкретна цел",
"Dark": "Тъмен", "Dark": "Тъмен",
"Dashboard": "",
"Database": "База данни", "Database": "База данни",
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm", "DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
"December": "",
"Default": "По подразбиране", "Default": "По подразбиране",
"Default (Automatic1111)": "По подразбиране (Automatic1111)", "Default (Automatic1111)": "По подразбиране (Automatic1111)",
"Default (SentenceTransformers)": "", "Default (SentenceTransformers)": "",
...@@ -118,6 +132,7 @@ ...@@ -118,6 +132,7 @@
"Delete chat": "Изтриване на чат", "Delete chat": "Изтриване на чат",
"Delete Chat": "", "Delete Chat": "",
"Delete Chats": "Изтриване на Чатове", "Delete Chats": "Изтриване на Чатове",
"delete this link": "",
"Delete User": "", "Delete User": "",
"Deleted {{deleteModelTag}}": "Изтрито {{deleteModelTag}}", "Deleted {{deleteModelTag}}": "Изтрито {{deleteModelTag}}",
"Deleted {{tagName}}": "", "Deleted {{tagName}}": "",
...@@ -137,6 +152,7 @@ ...@@ -137,6 +152,7 @@
"Don't have an account?": "Нямате акаунт?", "Don't have an account?": "Нямате акаунт?",
"Don't like the style": "", "Don't like the style": "",
"Download": "", "Download": "",
"Download canceled": "",
"Download Database": "Сваляне на база данни", "Download Database": "Сваляне на база данни",
"Drop any files here to add to the conversation": "Пускане на файлове тук, за да ги добавите в чата", "Drop any files here to add to the conversation": "Пускане на файлове тук, за да ги добавите в чата",
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "напр. '30с','10м'. Валидни единици са 'с', 'м', 'ч'.", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "напр. '30с','10м'. Валидни единици са 'с', 'м', 'ч'.",
...@@ -144,6 +160,7 @@ ...@@ -144,6 +160,7 @@
"Edit Doc": "Редактиране на документ", "Edit Doc": "Редактиране на документ",
"Edit User": "Редактиране на потребител", "Edit User": "Редактиране на потребител",
"Email": "Имейл", "Email": "Имейл",
"Embedding Model": "",
"Embedding Model Engine": "", "Embedding Model Engine": "",
"Embedding model set to \"{{embedding_model}}\"": "", "Embedding model set to \"{{embedding_model}}\"": "",
"Enable Chat History": "Вклюване на Чат История", "Enable Chat History": "Вклюване на Чат История",
...@@ -154,6 +171,7 @@ ...@@ -154,6 +171,7 @@
"Enter Chunk Overlap": "Въведете Chunk Overlap", "Enter Chunk Overlap": "Въведете Chunk Overlap",
"Enter Chunk Size": "Въведете Chunk Size", "Enter Chunk Size": "Въведете Chunk Size",
"Enter Image Size (e.g. 512x512)": "Въведете размер на изображението (напр. 512x512)", "Enter Image Size (e.g. 512x512)": "Въведете размер на изображението (напр. 512x512)",
"Enter language codes": "",
"Enter LiteLLM API Base URL (litellm_params.api_base)": "Въведете LiteLLM API Base URL (litellm_params.api_base)", "Enter LiteLLM API Base URL (litellm_params.api_base)": "Въведете LiteLLM API Base URL (litellm_params.api_base)",
"Enter LiteLLM API Key (litellm_params.api_key)": "Въведете LiteLLM API Key (litellm_params.api_key)", "Enter LiteLLM API Key (litellm_params.api_key)": "Въведете LiteLLM API Key (litellm_params.api_key)",
"Enter LiteLLM API RPM (litellm_params.rpm)": "Въведете LiteLLM API RPM (litellm_params.rpm)", "Enter LiteLLM API RPM (litellm_params.rpm)": "Въведете LiteLLM API RPM (litellm_params.rpm)",
...@@ -165,6 +183,7 @@ ...@@ -165,6 +183,7 @@
"Enter stop sequence": "Въведете стоп последователност", "Enter stop sequence": "Въведете стоп последователност",
"Enter Top K": "Въведете Top K", "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://127.0.0.1:7860/)": "Въведете URL (напр. http://127.0.0.1:7860/)",
"Enter URL (e.g. http://localhost:11434)": "",
"Enter Your Email": "Въведете имейл", "Enter Your Email": "Въведете имейл",
"Enter Your Full Name": "Въведете вашето пълно име", "Enter Your Full Name": "Въведете вашето пълно име",
"Enter Your Password": "Въведете вашата парола", "Enter Your Password": "Въведете вашата парола",
...@@ -177,6 +196,7 @@ ...@@ -177,6 +196,7 @@
"Export Prompts": "Експортване на промптове", "Export Prompts": "Експортване на промптове",
"Failed to create API Key.": "", "Failed to create API Key.": "",
"Failed to read clipboard contents": "Грешка при четене на съдържанието от клипборда", "Failed to read clipboard contents": "Грешка при четене на съдържанието от клипборда",
"February": "",
"Feel free to add specific details": "", "Feel free to add specific details": "",
"File Mode": "Файл Мод", "File Mode": "Файл Мод",
"File not found.": "Файл не е намерен.", "File not found.": "Файл не е намерен.",
...@@ -193,6 +213,7 @@ ...@@ -193,6 +213,7 @@
"Good Response": "", "Good Response": "",
"has no conversations.": "", "has no conversations.": "",
"Hello, {{name}}": "Здравей, {{name}}", "Hello, {{name}}": "Здравей, {{name}}",
"Help": "",
"Hide": "Скрий", "Hide": "Скрий",
"Hide Additional Params": "Скрий допълнителни параметри", "Hide Additional Params": "Скрий допълнителни параметри",
"How can I help you today?": "Как мога да ви помогна днес?", "How can I help you today?": "Как мога да ви помогна днес?",
...@@ -206,9 +227,14 @@ ...@@ -206,9 +227,14 @@
"Import Modelfiles": "Импортване на модфайлове", "Import Modelfiles": "Импортване на модфайлове",
"Import Prompts": "Импортване на промптове", "Import Prompts": "Импортване на промптове",
"Include `--api` flag when running stable-diffusion-webui": "Включете флага `--api`, когато стартирате stable-diffusion-webui", "Include `--api` flag when running stable-diffusion-webui": "Включете флага `--api`, когато стартирате stable-diffusion-webui",
"Input commands": "",
"Interface": "Интерфейс", "Interface": "Интерфейс",
"Invalid Tag": "",
"January": "",
"join our Discord for help.": "свържете се с нашия Discord за помощ.", "join our Discord for help.": "свържете се с нашия Discord за помощ.",
"JSON": "JSON", "JSON": "JSON",
"July": "",
"June": "",
"JWT Expiration": "JWT Expiration", "JWT Expiration": "JWT Expiration",
"JWT Token": "JWT Token", "JWT Token": "JWT Token",
"Keep Alive": "Keep Alive", "Keep Alive": "Keep Alive",
...@@ -223,8 +249,11 @@ ...@@ -223,8 +249,11 @@
"Manage LiteLLM Models": "Управление на LiteLLM Моделите", "Manage LiteLLM Models": "Управление на LiteLLM Моделите",
"Manage Models": "Управление на Моделите", "Manage Models": "Управление на Моделите",
"Manage Ollama Models": "Управление на Ollama Моделите", "Manage Ollama Models": "Управление на Ollama Моделите",
"March": "",
"Max Tokens": "Max Tokens", "Max Tokens": "Max Tokens",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимум 3 модели могат да бъдат сваляни едновременно. Моля, опитайте отново по-късно.", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимум 3 модели могат да бъдат сваляни едновременно. Моля, опитайте отново по-късно.",
"May": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Minimum Score": "", "Minimum Score": "",
"Mirostat": "Mirostat", "Mirostat": "Mirostat",
"Mirostat Eta": "Mirostat Eta", "Mirostat Eta": "Mirostat Eta",
...@@ -255,11 +284,15 @@ ...@@ -255,11 +284,15 @@
"Name your modelfile": "Име на модфайла", "Name your modelfile": "Име на модфайла",
"New Chat": "Нов чат", "New Chat": "Нов чат",
"New Password": "Нова парола", "New Password": "Нова парола",
"No results found": "",
"No source available": "",
"Not factually correct": "", "Not factually correct": "",
"Not sure what to add?": "Не сте сигурни, какво да добавите?", "Not sure what to add?": "Не сте сигурни, какво да добавите?",
"Not sure what to write? Switch to": "Не сте сигурни, какво да напишете? Превключете към", "Not sure what to write? Switch to": "Не сте сигурни, какво да напишете? Превключете към",
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "",
"Notifications": "Десктоп Известия", "Notifications": "Десктоп Известия",
"November": "",
"October": "",
"Off": "Изкл.", "Off": "Изкл.",
"Okay, Let's Go!": "ОК, Нека започваме!", "Okay, Let's Go!": "ОК, Нека започваме!",
"OLED Dark": "", "OLED Dark": "",
...@@ -283,6 +316,7 @@ ...@@ -283,6 +316,7 @@
"OpenAI URL/Key required.": "", "OpenAI URL/Key required.": "",
"or": "или", "or": "или",
"Other": "", "Other": "",
"Overview": "",
"Parameters": "Параметри", "Parameters": "Параметри",
"Password": "Парола", "Password": "Парола",
"PDF document (.pdf)": "", "PDF document (.pdf)": "",
...@@ -292,11 +326,15 @@ ...@@ -292,11 +326,15 @@
"Plain text (.txt)": "", "Plain text (.txt)": "",
"Playground": "Плейграунд", "Playground": "Плейграунд",
"Positive attitude": "", "Positive attitude": "",
"Previous 30 days": "",
"Previous 7 days": "",
"Profile Image": "", "Profile Image": "",
"Prompt": "",
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "", "Prompt (e.g. Tell me a fun fact about the Roman Empire)": "",
"Prompt Content": "Съдържание на промпта", "Prompt Content": "Съдържание на промпта",
"Prompt suggestions": "Промпт предложения", "Prompt suggestions": "Промпт предложения",
"Prompts": "Промптове", "Prompts": "Промптове",
"Pull \"{{searchValue}}\" from Ollama.com": "",
"Pull a model from Ollama.com": "Издърпайте модел от Ollama.com", "Pull a model from Ollama.com": "Издърпайте модел от Ollama.com",
"Pull Progress": "Прогрес на издърпването", "Pull Progress": "Прогрес на издърпването",
"Query Params": "Query Параметри", "Query Params": "Query Параметри",
...@@ -309,9 +347,12 @@ ...@@ -309,9 +347,12 @@
"Regenerate": "", "Regenerate": "",
"Release Notes": "Бележки по изданието", "Release Notes": "Бележки по изданието",
"Remove": "", "Remove": "",
"Remove Model": "",
"Rename": "",
"Repeat Last N": "Repeat Last N", "Repeat Last N": "Repeat Last N",
"Repeat Penalty": "Repeat Penalty", "Repeat Penalty": "Repeat Penalty",
"Request Mode": "Request Mode", "Request Mode": "Request Mode",
"Reranking Model": "",
"Reranking model disabled": "", "Reranking model disabled": "",
"Reranking model set to \"{{reranking_model}}\"": "", "Reranking model set to \"{{reranking_model}}\"": "",
"Reset Vector Storage": "Ресет Vector Storage", "Reset Vector Storage": "Ресет Vector Storage",
...@@ -337,12 +378,17 @@ ...@@ -337,12 +378,17 @@
"Select a mode": "Изберете режим", "Select a mode": "Изберете режим",
"Select a model": "Изберете модел", "Select a model": "Изберете модел",
"Select an Ollama instance": "Изберете Ollama инстанция", "Select an Ollama instance": "Изберете Ollama инстанция",
"Select model": "",
"Send a Message": "Изпращане на Съобщение", "Send a Message": "Изпращане на Съобщение",
"Send message": "Изпращане на съобщение", "Send message": "Изпращане на съобщение",
"September": "",
"Server connection verified": "Server connection verified", "Server connection verified": "Server connection verified",
"Set as default": "Задай по подразбиране", "Set as default": "Задай по подразбиране",
"Set Default Model": "Задай Модел По Подразбиране", "Set Default Model": "Задай Модел По Подразбиране",
"Set embedding model (e.g. {{model}})": "",
"Set Image Size": "Задай Размер на Изображението", "Set Image Size": "Задай Размер на Изображението",
"Set Model": "Задай Модел",
"Set reranking model (e.g. {{model}})": "",
"Set Steps": "Задай Стъпки", "Set Steps": "Задай Стъпки",
"Set Title Auto-Generation Model": "Задай Модел за Автоматично Генериране на Заглавие", "Set Title Auto-Generation Model": "Задай Модел за Автоматично Генериране на Заглавие",
"Set Voice": "Задай Глас", "Set Voice": "Задай Глас",
...@@ -361,6 +407,7 @@ ...@@ -361,6 +407,7 @@
"Sign Out": "Изход", "Sign Out": "Изход",
"Sign up": "Регистрация", "Sign up": "Регистрация",
"Signing in": "", "Signing in": "",
"Source": "",
"Speech recognition error: {{error}}": "Speech recognition error: {{error}}", "Speech recognition error: {{error}}": "Speech recognition error: {{error}}",
"Speech-to-Text Engine": "Speech-to-Text Engine", "Speech-to-Text Engine": "Speech-to-Text Engine",
"SpeechRecognition API is not supported in this browser.": "SpeechRecognition API is not supported in this browser.", "SpeechRecognition API is not supported in this browser.": "SpeechRecognition API is not supported in this browser.",
...@@ -370,6 +417,7 @@ ...@@ -370,6 +417,7 @@
"Subtitle (e.g. about the Roman Empire)": "", "Subtitle (e.g. about the Roman Empire)": "",
"Success": "Успех", "Success": "Успех",
"Successfully updated.": "Успешно обновено.", "Successfully updated.": "Успешно обновено.",
"Suggested": "",
"Sync All": "Синхронизиране на всички", "Sync All": "Синхронизиране на всички",
"System": "Система", "System": "Система",
"System Prompt": "Системен Промпт", "System Prompt": "Системен Промпт",
...@@ -390,11 +438,13 @@ ...@@ -390,11 +438,13 @@
"Title": "Заглавие", "Title": "Заглавие",
"Title (e.g. Tell me a fun fact)": "", "Title (e.g. Tell me a fun fact)": "",
"Title Auto-Generation": "Автоматично Генериране на Заглавие", "Title Auto-Generation": "Автоматично Генериране на Заглавие",
"Title cannot be an empty string.": "",
"Title Generation Prompt": "Промпт за Генериране на Заглавие", "Title Generation Prompt": "Промпт за Генериране на Заглавие",
"to": "в", "to": "в",
"To access the available model names for downloading,": "За да получите достъп до наличните имена на модели за изтегляне,", "To access the available model names for downloading,": "За да получите достъп до наличните имена на модели за изтегляне,",
"To access the GGUF models available for downloading,": "За да получите достъп до GGUF моделите, налични за изтегляне,", "To access the GGUF models available for downloading,": "За да получите достъп до GGUF моделите, налични за изтегляне,",
"to chat input.": "към чат входа.", "to chat input.": "към чат входа.",
"Today": "",
"Toggle settings": "Toggle settings", "Toggle settings": "Toggle settings",
"Toggle sidebar": "Toggle sidebar", "Toggle sidebar": "Toggle sidebar",
"Top K": "Top K", "Top K": "Top K",
...@@ -405,11 +455,7 @@ ...@@ -405,11 +455,7 @@
"Uh-oh! There was an issue connecting to {{provider}}.": "О, не! Възникна проблем при свързването с {{provider}}.", "Uh-oh! There was an issue connecting to {{provider}}.": "О, не! Възникна проблем при свързването с {{provider}}.",
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Непознат файлов тип '{{file_type}}', но се приема и обработва като текст", "Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Непознат файлов тип '{{file_type}}', но се приема и обработва като текст",
"Update and Copy Link": "", "Update and Copy Link": "",
"Update Embedding Model": "",
"Update embedding model (e.g. {{model}})": "",
"Update password": "Обновяване на парола", "Update password": "Обновяване на парола",
"Update Reranking Model": "",
"Update reranking model (e.g. {{model}})": "",
"Upload a GGUF model": "Качване на GGUF модел", "Upload a GGUF model": "Качване на GGUF модел",
"Upload files": "Качване на файлове", "Upload files": "Качване на файлове",
"Upload Progress": "Прогрес на качването", "Upload Progress": "Прогрес на качването",
...@@ -427,6 +473,8 @@ ...@@ -427,6 +473,8 @@
"Version": "Версия", "Version": "Версия",
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "", "Warning: If you update or change your embedding model, you will need to re-import all documents.": "",
"Web": "Уеб", "Web": "Уеб",
"Web Loader Settings": "",
"Web Params": "",
"Webhook URL": "", "Webhook URL": "",
"WebUI Add-ons": "WebUI Добавки", "WebUI Add-ons": "WebUI Добавки",
"WebUI Settings": "WebUI Настройки", "WebUI Settings": "WebUI Настройки",
...@@ -436,8 +484,12 @@ ...@@ -436,8 +484,12 @@
"Whisper (Local)": "Whisper (Локален)", "Whisper (Local)": "Whisper (Локален)",
"Write a prompt suggestion (e.g. Who are you?)": "Напиши предложение за промпт (напр. Кой сте вие?)", "Write a prompt suggestion (e.g. Who are you?)": "Напиши предложение за промпт (напр. Кой сте вие?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Напиши описание в 50 знака, което описва [тема или ключова дума].", "Write a summary in 50 words that summarizes [topic or keyword].": "Напиши описание в 50 знака, което описва [тема или ключова дума].",
"Yesterday": "",
"You": "Вие", "You": "Вие",
"You have no archived conversations.": "",
"You have shared this chat": "",
"You're a helpful assistant.": "Вие сте полезен асистент.", "You're a helpful assistant.": "Вие сте полезен асистент.",
"You're now logged in.": "Сега, вие влязохте в системата.", "You're now logged in.": "Сега, вие влязохте в системата.",
"Youtube": "" "Youtube": "",
"Youtube Loader Settings": ""
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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