forked from open-webui/open-webui
Merge branch 'dev' into feat/customizable-title-prompt-length
This commit is contained in:
commit
a938ffb586
16 changed files with 187 additions and 43 deletions
|
@ -28,6 +28,7 @@ from config import (
|
|||
UPLOAD_DIR,
|
||||
WHISPER_MODEL,
|
||||
WHISPER_MODEL_DIR,
|
||||
WHISPER_MODEL_AUTO_UPDATE,
|
||||
DEVICE_TYPE,
|
||||
)
|
||||
|
||||
|
@ -69,12 +70,24 @@ def transcribe(
|
|||
f.write(contents)
|
||||
f.close()
|
||||
|
||||
model = WhisperModel(
|
||||
WHISPER_MODEL,
|
||||
device=whisper_device_type,
|
||||
compute_type="int8",
|
||||
download_root=WHISPER_MODEL_DIR,
|
||||
whisper_kwargs = {
|
||||
"model_size_or_path": WHISPER_MODEL,
|
||||
"device": whisper_device_type,
|
||||
"compute_type": "int8",
|
||||
"download_root": WHISPER_MODEL_DIR,
|
||||
"local_files_only": not WHISPER_MODEL_AUTO_UPDATE,
|
||||
}
|
||||
|
||||
log.debug(f"whisper_kwargs: {whisper_kwargs}")
|
||||
|
||||
try:
|
||||
model = WhisperModel(**whisper_kwargs)
|
||||
except:
|
||||
log.warning(
|
||||
"WhisperModel initialization failed, attempting download with local_files_only=False"
|
||||
)
|
||||
whisper_kwargs["local_files_only"] = False
|
||||
model = WhisperModel(**whisper_kwargs)
|
||||
|
||||
segments, info = model.transcribe(file_path, beam_size=5)
|
||||
log.info(
|
||||
|
|
|
@ -29,7 +29,13 @@ import base64
|
|||
import json
|
||||
import logging
|
||||
|
||||
from config import SRC_LOG_LEVELS, CACHE_DIR, AUTOMATIC1111_BASE_URL, COMFYUI_BASE_URL
|
||||
from config import (
|
||||
SRC_LOG_LEVELS,
|
||||
CACHE_DIR,
|
||||
ENABLE_IMAGE_GENERATION,
|
||||
AUTOMATIC1111_BASE_URL,
|
||||
COMFYUI_BASE_URL,
|
||||
)
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -48,7 +54,7 @@ app.add_middleware(
|
|||
)
|
||||
|
||||
app.state.ENGINE = ""
|
||||
app.state.ENABLED = False
|
||||
app.state.ENABLED = ENABLE_IMAGE_GENERATION
|
||||
|
||||
app.state.OPENAI_API_KEY = ""
|
||||
app.state.MODEL = ""
|
||||
|
|
|
@ -612,8 +612,13 @@ async def generate_embeddings(
|
|||
user=Depends(get_current_user),
|
||||
):
|
||||
if url_idx == None:
|
||||
if form_data.model in app.state.MODELS:
|
||||
url_idx = random.choice(app.state.MODELS[form_data.model]["urls"])
|
||||
model = form_data.model
|
||||
|
||||
if ":" not in model:
|
||||
model = f"{model}:latest"
|
||||
|
||||
if model in app.state.MODELS:
|
||||
url_idx = random.choice(app.state.MODELS[model]["urls"])
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
|
@ -672,8 +677,13 @@ async def generate_completion(
|
|||
):
|
||||
|
||||
if url_idx == None:
|
||||
if form_data.model in app.state.MODELS:
|
||||
url_idx = random.choice(app.state.MODELS[form_data.model]["urls"])
|
||||
model = form_data.model
|
||||
|
||||
if ":" not in model:
|
||||
model = f"{model}:latest"
|
||||
|
||||
if model in app.state.MODELS:
|
||||
url_idx = random.choice(app.state.MODELS[model]["urls"])
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
|
@ -770,8 +780,13 @@ async def generate_chat_completion(
|
|||
):
|
||||
|
||||
if url_idx == None:
|
||||
if form_data.model in app.state.MODELS:
|
||||
url_idx = random.choice(app.state.MODELS[form_data.model]["urls"])
|
||||
model = form_data.model
|
||||
|
||||
if ":" not in model:
|
||||
model = f"{model}:latest"
|
||||
|
||||
if model in app.state.MODELS:
|
||||
url_idx = random.choice(app.state.MODELS[model]["urls"])
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
|
@ -874,8 +889,13 @@ async def generate_openai_chat_completion(
|
|||
):
|
||||
|
||||
if url_idx == None:
|
||||
if form_data.model in app.state.MODELS:
|
||||
url_idx = random.choice(app.state.MODELS[form_data.model]["urls"])
|
||||
model = form_data.model
|
||||
|
||||
if ":" not in model:
|
||||
model = f"{model}:latest"
|
||||
|
||||
if model in app.state.MODELS:
|
||||
url_idx = random.choice(app.state.MODELS[model]["urls"])
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
|
|
|
@ -413,7 +413,7 @@ RAG_EMBEDDING_MODEL_AUTO_UPDATE = (
|
|||
)
|
||||
|
||||
|
||||
# device type embbeding models - "cpu" (default), "cuda" (nvidia gpu required) or "mps" (apple silicon) - choosing this right can lead to better performance
|
||||
# device type embedding models - "cpu" (default), "cuda" (nvidia gpu required) or "mps" (apple silicon) - choosing this right can lead to better performance
|
||||
USE_CUDA = os.environ.get("USE_CUDA_DOCKER", "false")
|
||||
|
||||
if USE_CUDA.lower() == "true":
|
||||
|
@ -450,11 +450,17 @@ Query: [query]"""
|
|||
|
||||
WHISPER_MODEL = os.getenv("WHISPER_MODEL", "base")
|
||||
WHISPER_MODEL_DIR = os.getenv("WHISPER_MODEL_DIR", f"{CACHE_DIR}/whisper/models")
|
||||
WHISPER_MODEL_AUTO_UPDATE = (
|
||||
os.environ.get("WHISPER_MODEL_AUTO_UPDATE", "").lower() == "true"
|
||||
)
|
||||
|
||||
|
||||
####################################
|
||||
# Images
|
||||
####################################
|
||||
|
||||
ENABLE_IMAGE_GENERATION = (
|
||||
os.environ.get("ENABLE_IMAGE_GENERATION", "").lower() == "true"
|
||||
)
|
||||
AUTOMATIC1111_BASE_URL = os.getenv("AUTOMATIC1111_BASE_URL", "")
|
||||
COMFYUI_BASE_URL = os.getenv("COMFYUI_BASE_URL", "")
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<link rel="manifest" href="%sveltekit.assets%/manifest.json" />
|
||||
<link rel="manifest" href="%sveltekit.assets%/manifest.json" crossorigin="use-credentials" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
<script>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
import { synthesizeOpenAISpeech } from '$lib/apis/openai';
|
||||
import { imageGenerations } from '$lib/apis/images';
|
||||
import {
|
||||
approximateToHumanReadable,
|
||||
extractSentences,
|
||||
revertSanitizedResponseContent,
|
||||
sanitizeResponseContent
|
||||
|
@ -122,7 +123,10 @@
|
|||
eval_count: ${message.info.eval_count ?? 'N/A'}<br/>
|
||||
eval_duration: ${
|
||||
Math.round(((message.info.eval_duration ?? 0) / 1000000) * 100) / 100 ?? 'N/A'
|
||||
}ms</span>`,
|
||||
}ms<br/>
|
||||
approximate_total: ${approximateToHumanReadable(
|
||||
message.info.total_duration
|
||||
)}</span>`,
|
||||
allowHTML: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
: items;
|
||||
|
||||
const pullModelHandler = async () => {
|
||||
const sanitizedModelTag = searchValue.trim();
|
||||
const sanitizedModelTag = searchValue.trim().replace(/^ollama\s+(run|pull)\s+/, '');
|
||||
|
||||
console.log($MODEL_DOWNLOAD_POOL);
|
||||
if ($MODEL_DOWNLOAD_POOL[sanitizedModelTag]) {
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
};
|
||||
|
||||
const pullModelHandler = async () => {
|
||||
const sanitizedModelTag = modelTag.trim();
|
||||
const sanitizedModelTag = modelTag.trim().replace(/^ollama\s+(run|pull)\s+/, '');
|
||||
if (modelDownloadStatus[sanitizedModelTag]) {
|
||||
toast.error(
|
||||
$i18n.t(`Model '{{modelTag}}' is already in queue for downloading.`, {
|
||||
|
|
42
src/lib/components/common/Pagination.svelte
Normal file
42
src/lib/components/common/Pagination.svelte
Normal file
|
@ -0,0 +1,42 @@
|
|||
<script lang="ts">
|
||||
import { Pagination } from 'bits-ui';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
import ChevronLeft from '../icons/ChevronLeft.svelte';
|
||||
import ChevronRight from '../icons/ChevronRight.svelte';
|
||||
|
||||
export let page = 0;
|
||||
export let count = 0;
|
||||
export let perPage = 20;
|
||||
</script>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<Pagination.Root bind:page {count} {perPage} let:pages>
|
||||
<div class="my-2 flex items-center">
|
||||
<Pagination.PrevButton
|
||||
class="mr-[25px] inline-flex size-8 items-center justify-center rounded-[9px] bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 active:scale-98 disabled:cursor-not-allowed disabled:text-gray-400 dark:disabled:text-gray-700 hover:disabled:bg-transparent dark:hover:disabled:bg-transparent"
|
||||
>
|
||||
<ChevronLeft className="size-4" strokeWidth="2" />
|
||||
</Pagination.PrevButton>
|
||||
<div class="flex items-center gap-2.5">
|
||||
{#each pages as page (page.key)}
|
||||
{#if page.type === 'ellipsis'}
|
||||
<div class="text-sm font-medium text-foreground-alt">...</div>
|
||||
{:else}
|
||||
<Pagination.Page
|
||||
{page}
|
||||
class="inline-flex size-8 items-center justify-center rounded-[9px] bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-sm font-medium hover:bg-dark-10 active:scale-98 disabled:cursor-not-allowed disabled:opacity-50 hover:disabled:bg-transparent data-[selected]:bg-black data-[selected]:text-gray-100 data-[selected]:hover:bg-black dark:data-[selected]:bg-white dark:data-[selected]:text-gray-900 dark:data-[selected]:hover:bg-white"
|
||||
>
|
||||
{page.value}
|
||||
</Pagination.Page>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
<Pagination.NextButton
|
||||
class="ml-[25px] inline-flex size-8 items-center justify-center rounded-[9px] bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 active:scale-98 disabled:cursor-not-allowed disabled:text-gray-400 dark:disabled:text-gray-700 hover:disabled:bg-transparent dark:hover:disabled:bg-transparent"
|
||||
>
|
||||
<ChevronRight className="size-4" strokeWidth="2" />
|
||||
</Pagination.NextButton>
|
||||
</div>
|
||||
</Pagination.Root>
|
||||
</div>
|
15
src/lib/components/icons/ChevronLeft.svelte
Normal file
15
src/lib/components/icons/ChevronLeft.svelte
Normal file
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
export let className = 'w-4 h-4';
|
||||
export let strokeWidth = '1.5';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width={strokeWidth}
|
||||
stroke="currentColor"
|
||||
class={className}
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5" />
|
||||
</svg>
|
15
src/lib/components/icons/ChevronRight.svelte
Normal file
15
src/lib/components/icons/ChevronRight.svelte
Normal file
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
export let className = 'w-4 h-4';
|
||||
export let strokeWidth = '1.5';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width={strokeWidth}
|
||||
stroke="currentColor"
|
||||
class={className}
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5" />
|
||||
</svg>
|
|
@ -26,14 +26,14 @@
|
|||
|
||||
<div slot="content">
|
||||
<DropdownMenu.Content
|
||||
class="w-full max-w-[130px] rounded-lg px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow"
|
||||
class="w-full max-w-[150px] rounded-lg px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-900 dark:text-white shadow"
|
||||
sideOffset={-2}
|
||||
side="bottom"
|
||||
align="start"
|
||||
transition={flyAndScale}
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer"
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer dark:hover:bg-gray-850 rounded-md"
|
||||
on:click={() => {
|
||||
renameHandler();
|
||||
}}
|
||||
|
@ -43,7 +43,7 @@
|
|||
</DropdownMenu.Item>
|
||||
|
||||
<DropdownMenu.Item
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer"
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer dark:hover:bg-gray-850 rounded-md"
|
||||
on:click={() => {
|
||||
deleteHandler();
|
||||
}}
|
||||
|
|
|
@ -55,9 +55,9 @@
|
|||
"Check for updates": "Kiểm tra cập nhật",
|
||||
"Checking for updates...": "Đang kiểm tra cập nhật...",
|
||||
"Choose a model before saving...": "Chọn mô hình trước khi lưu...",
|
||||
"Chunk Overlap": "Kích thước chồng lấn (overlap)",
|
||||
"Chunk Overlap": "Chồng lấn (overlap)",
|
||||
"Chunk Params": "Cài đặt số lượng ký tự cho khối ký tự (chunk)",
|
||||
"Chunk Size": "Kích thức khối (size)",
|
||||
"Chunk Size": "Kích thước khối (size)",
|
||||
"Click here for help.": "Bấm vào đây để được trợ giúp.",
|
||||
"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",
|
||||
|
@ -65,7 +65,7 @@
|
|||
"click here.": "bấm vào đây.",
|
||||
"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": "Bộ sưu tập",
|
||||
"Collection": "Tổng hợp mọi tài liệu",
|
||||
"Command": "Lệnh",
|
||||
"Confirm Password": "Xác nhận Mật khẩu",
|
||||
"Connections": "Kết nối",
|
||||
|
@ -76,7 +76,7 @@
|
|||
"Copy last response": "Sao chép phản hồi cuối cùng",
|
||||
"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ả mô hình",
|
||||
"Create a modelfile": "Tạo tệp mô tả cho mô hình",
|
||||
"Create Account": "Tạo Tài khoản",
|
||||
"Created at": "Được tạo vào lúc",
|
||||
"Created by": "Được tạo bởi",
|
||||
|
@ -347,7 +347,7 @@
|
|||
"Valid time units:": "Đơn vị thời gian hợp lệ:",
|
||||
"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": "Phiên bản",
|
||||
"Version": "Version",
|
||||
"Web": "Web",
|
||||
"WebUI Add-ons": "Tiện ích WebUI",
|
||||
"WebUI Settings": "Cài đặt WebUI",
|
||||
|
|
|
@ -493,4 +493,25 @@ export const templatePrompt = (template: string, prompt: string) => {
|
|||
}
|
||||
|
||||
return template;
|
||||
|
||||
export const approximateToHumanReadable = (nanoseconds: number) => {
|
||||
const seconds = Math.floor((nanoseconds / 1e9) % 60);
|
||||
const minutes = Math.floor((nanoseconds / 6e10) % 60);
|
||||
const hours = Math.floor((nanoseconds / 3.6e12) % 24);
|
||||
|
||||
const results: string[] = [];
|
||||
|
||||
if (seconds >= 0) {
|
||||
results.push(`${seconds}s`);
|
||||
}
|
||||
|
||||
if (minutes > 0) {
|
||||
results.push(`${minutes}m`);
|
||||
}
|
||||
|
||||
if (hours > 0) {
|
||||
results.push(`${hours}h`);
|
||||
}
|
||||
|
||||
return results.reverse().join(' ');
|
||||
};
|
||||
|
|
|
@ -106,11 +106,6 @@
|
|||
// IndexedDB Not Found
|
||||
}
|
||||
|
||||
console.log();
|
||||
|
||||
await models.set(await getModels());
|
||||
await tick();
|
||||
|
||||
await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
|
||||
|
||||
await modelfiles.set(await getModelfiles(localStorage.token));
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths';
|
||||
import EditUserModal from '$lib/components/admin/EditUserModal.svelte';
|
||||
import SettingsModal from '$lib/components/admin/SettingsModal.svelte';
|
||||
import Pagination from '$lib/components/common/Pagination.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
|
@ -21,6 +22,8 @@
|
|||
let search = '';
|
||||
let selectedUser = null;
|
||||
|
||||
let page = 1;
|
||||
|
||||
let showSettingsModal = false;
|
||||
let showEditUserModal = false;
|
||||
|
||||
|
@ -159,7 +162,8 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each users.filter((user) => {
|
||||
{#each users
|
||||
.filter((user) => {
|
||||
if (search === '') {
|
||||
return true;
|
||||
} else {
|
||||
|
@ -167,7 +171,8 @@
|
|||
const query = search.toLowerCase();
|
||||
return name.includes(query);
|
||||
}
|
||||
}) as user}
|
||||
})
|
||||
.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
|
||||
|
@ -270,6 +275,8 @@
|
|||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue