Merge branch 'dev' into feat/customizable-title-prompt-length

This commit is contained in:
Timothy Jaeryang Baek 2024-04-14 14:02:53 -07:00 committed by GitHub
commit a938ffb586
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 187 additions and 43 deletions

View file

@ -28,6 +28,7 @@ from config import (
UPLOAD_DIR, UPLOAD_DIR,
WHISPER_MODEL, WHISPER_MODEL,
WHISPER_MODEL_DIR, WHISPER_MODEL_DIR,
WHISPER_MODEL_AUTO_UPDATE,
DEVICE_TYPE, DEVICE_TYPE,
) )
@ -69,12 +70,24 @@ def transcribe(
f.write(contents) f.write(contents)
f.close() f.close()
model = WhisperModel( whisper_kwargs = {
WHISPER_MODEL, "model_size_or_path": WHISPER_MODEL,
device=whisper_device_type, "device": whisper_device_type,
compute_type="int8", "compute_type": "int8",
download_root=WHISPER_MODEL_DIR, "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) segments, info = model.transcribe(file_path, beam_size=5)
log.info( log.info(

View file

@ -29,7 +29,13 @@ import base64
import json import json
import logging 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__) log = logging.getLogger(__name__)
@ -48,7 +54,7 @@ app.add_middleware(
) )
app.state.ENGINE = "" app.state.ENGINE = ""
app.state.ENABLED = False app.state.ENABLED = ENABLE_IMAGE_GENERATION
app.state.OPENAI_API_KEY = "" app.state.OPENAI_API_KEY = ""
app.state.MODEL = "" app.state.MODEL = ""

View file

@ -612,8 +612,13 @@ async def generate_embeddings(
user=Depends(get_current_user), user=Depends(get_current_user),
): ):
if url_idx == None: if url_idx == None:
if form_data.model in app.state.MODELS: model = form_data.model
url_idx = random.choice(app.state.MODELS[form_data.model]["urls"])
if ":" not in model:
model = f"{model}:latest"
if model in app.state.MODELS:
url_idx = random.choice(app.state.MODELS[model]["urls"])
else: else:
raise HTTPException( raise HTTPException(
status_code=400, status_code=400,
@ -672,8 +677,13 @@ async def generate_completion(
): ):
if url_idx == None: if url_idx == None:
if form_data.model in app.state.MODELS: model = form_data.model
url_idx = random.choice(app.state.MODELS[form_data.model]["urls"])
if ":" not in model:
model = f"{model}:latest"
if model in app.state.MODELS:
url_idx = random.choice(app.state.MODELS[model]["urls"])
else: else:
raise HTTPException( raise HTTPException(
status_code=400, status_code=400,
@ -770,8 +780,13 @@ async def generate_chat_completion(
): ):
if url_idx == None: if url_idx == None:
if form_data.model in app.state.MODELS: model = form_data.model
url_idx = random.choice(app.state.MODELS[form_data.model]["urls"])
if ":" not in model:
model = f"{model}:latest"
if model in app.state.MODELS:
url_idx = random.choice(app.state.MODELS[model]["urls"])
else: else:
raise HTTPException( raise HTTPException(
status_code=400, status_code=400,
@ -874,8 +889,13 @@ async def generate_openai_chat_completion(
): ):
if url_idx == None: if url_idx == None:
if form_data.model in app.state.MODELS: model = form_data.model
url_idx = random.choice(app.state.MODELS[form_data.model]["urls"])
if ":" not in model:
model = f"{model}:latest"
if model in app.state.MODELS:
url_idx = random.choice(app.state.MODELS[model]["urls"])
else: else:
raise HTTPException( raise HTTPException(
status_code=400, status_code=400,

View file

@ -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") USE_CUDA = os.environ.get("USE_CUDA_DOCKER", "false")
if USE_CUDA.lower() == "true": if USE_CUDA.lower() == "true":
@ -450,11 +450,17 @@ Query: [query]"""
WHISPER_MODEL = os.getenv("WHISPER_MODEL", "base") WHISPER_MODEL = os.getenv("WHISPER_MODEL", "base")
WHISPER_MODEL_DIR = os.getenv("WHISPER_MODEL_DIR", f"{CACHE_DIR}/whisper/models") 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 # Images
#################################### ####################################
ENABLE_IMAGE_GENERATION = (
os.environ.get("ENABLE_IMAGE_GENERATION", "").lower() == "true"
)
AUTOMATIC1111_BASE_URL = os.getenv("AUTOMATIC1111_BASE_URL", "") AUTOMATIC1111_BASE_URL = os.getenv("AUTOMATIC1111_BASE_URL", "")
COMFYUI_BASE_URL = os.getenv("COMFYUI_BASE_URL", "") COMFYUI_BASE_URL = os.getenv("COMFYUI_BASE_URL", "")

View file

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" /> <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="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<meta name="robots" content="noindex,nofollow" /> <meta name="robots" content="noindex,nofollow" />
<script> <script>

View file

@ -18,6 +18,7 @@
import { synthesizeOpenAISpeech } from '$lib/apis/openai'; import { synthesizeOpenAISpeech } from '$lib/apis/openai';
import { imageGenerations } from '$lib/apis/images'; import { imageGenerations } from '$lib/apis/images';
import { import {
approximateToHumanReadable,
extractSentences, extractSentences,
revertSanitizedResponseContent, revertSanitizedResponseContent,
sanitizeResponseContent sanitizeResponseContent
@ -122,7 +123,10 @@
eval_count: ${message.info.eval_count ?? 'N/A'}<br/> eval_count: ${message.info.eval_count ?? 'N/A'}<br/>
eval_duration: ${ eval_duration: ${
Math.round(((message.info.eval_duration ?? 0) / 1000000) * 100) / 100 ?? 'N/A' 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 allowHTML: true
}); });
} }

View file

@ -33,7 +33,7 @@
: items; : items;
const pullModelHandler = async () => { const pullModelHandler = async () => {
const sanitizedModelTag = searchValue.trim(); const sanitizedModelTag = searchValue.trim().replace(/^ollama\s+(run|pull)\s+/, '');
console.log($MODEL_DOWNLOAD_POOL); console.log($MODEL_DOWNLOAD_POOL);
if ($MODEL_DOWNLOAD_POOL[sanitizedModelTag]) { if ($MODEL_DOWNLOAD_POOL[sanitizedModelTag]) {

View file

@ -139,7 +139,7 @@
}; };
const pullModelHandler = async () => { const pullModelHandler = async () => {
const sanitizedModelTag = modelTag.trim(); const sanitizedModelTag = modelTag.trim().replace(/^ollama\s+(run|pull)\s+/, '');
if (modelDownloadStatus[sanitizedModelTag]) { if (modelDownloadStatus[sanitizedModelTag]) {
toast.error( toast.error(
$i18n.t(`Model '{{modelTag}}' is already in queue for downloading.`, { $i18n.t(`Model '{{modelTag}}' is already in queue for downloading.`, {

View 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>

View 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>

View 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>

View file

@ -26,14 +26,14 @@
<div slot="content"> <div slot="content">
<DropdownMenu.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} sideOffset={-2}
side="bottom" side="bottom"
align="start" align="start"
transition={flyAndScale} transition={flyAndScale}
> >
<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={() => { on:click={() => {
renameHandler(); renameHandler();
}} }}
@ -43,7 +43,7 @@
</DropdownMenu.Item> </DropdownMenu.Item>
<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={() => { on:click={() => {
deleteHandler(); deleteHandler();
}} }}

View file

@ -55,9 +55,9 @@
"Check for updates": "Kiểm tra cập nhật", "Check for updates": "Kiểm tra cập nhật",
"Checking for updates...": "Đang 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...", "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 Params": "Cài đặt số lượng ký tự cho khối ký tự (chunk)",
"Chunk Size": "Kích thc 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 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 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": "Bấm vào đây để chọn",
@ -65,7 +65,7 @@
"click here.": "bấm vào đây.", "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.", "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", "Close": "Đóng",
"Collection": "Bộ sưu tập", "Collection": "Tổng hợp mọi tài liệu",
"Command": "Lệnh", "Command": "Lệnh",
"Confirm Password": "Xác nhận Mật khẩu", "Confirm Password": "Xác nhận Mật khẩu",
"Connections": "Kết nối", "Connections": "Kết nối",
@ -76,7 +76,7 @@
"Copy last response": "Sao chép phản hồi cuối cùng", "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!", "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 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", "Create Account": "Tạo Tài khoản",
"Created at": "Được tạo vào lúc", "Created at": "Được tạo vào lúc",
"Created by": "Được tạo bởi", "Created by": "Được tạo bởi",
@ -347,7 +347,7 @@
"Valid time units:": "Đơn vị thời gian hợp lệ:", "Valid time units:": "Đơn vị thời gian hợp lệ:",
"variable": "biến", "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.", "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", "Web": "Web",
"WebUI Add-ons": "Tiện ích WebUI", "WebUI Add-ons": "Tiện ích WebUI",
"WebUI Settings": "Cài đặt WebUI", "WebUI Settings": "Cài đặt WebUI",

View file

@ -493,4 +493,25 @@ export const templatePrompt = (template: string, prompt: string) => {
} }
return template; 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(' ');
}; };

View file

@ -106,11 +106,6 @@
// IndexedDB Not Found // IndexedDB Not Found
} }
console.log();
await models.set(await getModels());
await tick();
await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}')); await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
await modelfiles.set(await getModelfiles(localStorage.token)); await modelfiles.set(await getModelfiles(localStorage.token));

View file

@ -12,6 +12,7 @@
import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths'; import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths';
import EditUserModal from '$lib/components/admin/EditUserModal.svelte'; import EditUserModal from '$lib/components/admin/EditUserModal.svelte';
import SettingsModal from '$lib/components/admin/SettingsModal.svelte'; import SettingsModal from '$lib/components/admin/SettingsModal.svelte';
import Pagination from '$lib/components/common/Pagination.svelte';
const i18n = getContext('i18n'); const i18n = getContext('i18n');
@ -21,6 +22,8 @@
let search = ''; let search = '';
let selectedUser = null; let selectedUser = null;
let page = 1;
let showSettingsModal = false; let showSettingsModal = false;
let showEditUserModal = false; let showEditUserModal = false;
@ -159,15 +162,17 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{#each users.filter((user) => { {#each users
if (search === '') { .filter((user) => {
return true; if (search === '') {
} else { return true;
let name = user.name.toLowerCase(); } else {
const query = search.toLowerCase(); let name = user.name.toLowerCase();
return name.includes(query); 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"> <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"> <td class="px-3 py-2 min-w-[7rem] w-28">
<button <button
@ -270,6 +275,8 @@
<div class=" text-gray-500 text-xs mt-2 text-right"> <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.")} {$i18n.t("Click on the user role button to change a user's role.")}
</div> </div>
<Pagination bind:page count={users.length} />
</div> </div>
</div> </div>
</div> </div>