feat: save user settings to db
This commit is contained in:
		
							parent
							
								
									9d4c07b76a
								
							
						
					
					
						commit
						ccbafca74c
					
				| 
						 | 
					@ -198,7 +198,7 @@ async def fetch_url(url, key):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def merge_models_lists(model_lists):
 | 
					def merge_models_lists(model_lists):
 | 
				
			||||||
    log.info(f"merge_models_lists {model_lists}")
 | 
					    log.debug(f"merge_models_lists {model_lists}")
 | 
				
			||||||
    merged_list = []
 | 
					    merged_list = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for idx, models in enumerate(model_lists):
 | 
					    for idx, models in enumerate(model_lists):
 | 
				
			||||||
| 
						 | 
					@ -237,7 +237,7 @@ async def get_all_models():
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        responses = await asyncio.gather(*tasks)
 | 
					        responses = await asyncio.gather(*tasks)
 | 
				
			||||||
        log.info(f"get_all_models:responses() {responses}")
 | 
					        log.debug(f"get_all_models:responses() {responses}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        models = {
 | 
					        models = {
 | 
				
			||||||
            "data": merge_models_lists(
 | 
					            "data": merge_models_lists(
 | 
				
			||||||
| 
						 | 
					@ -254,7 +254,7 @@ async def get_all_models():
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        log.info(f"models: {models}")
 | 
					        log.debug(f"models: {models}")
 | 
				
			||||||
        app.state.MODELS = {model["id"]: model for model in models["data"]}
 | 
					        app.state.MODELS = {model["id"]: model for model in models["data"]}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return models
 | 
					    return models
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					"""Peewee migrations -- 002_add_local_sharing.py.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Some examples (model - class or model name)::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    > Model = migrator.orm['table_name']            # Return model in current state by name
 | 
				
			||||||
 | 
					    > Model = migrator.ModelClass                   # Return model in current state by name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    > migrator.sql(sql)                             # Run custom SQL
 | 
				
			||||||
 | 
					    > migrator.run(func, *args, **kwargs)           # Run python function with the given args
 | 
				
			||||||
 | 
					    > migrator.create_model(Model)                  # Create a model (could be used as decorator)
 | 
				
			||||||
 | 
					    > migrator.remove_model(model, cascade=True)    # Remove a model
 | 
				
			||||||
 | 
					    > migrator.add_fields(model, **fields)          # Add fields to a model
 | 
				
			||||||
 | 
					    > migrator.change_fields(model, **fields)       # Change fields
 | 
				
			||||||
 | 
					    > migrator.remove_fields(model, *field_names, cascade=True)
 | 
				
			||||||
 | 
					    > migrator.rename_field(model, old_field_name, new_field_name)
 | 
				
			||||||
 | 
					    > migrator.rename_table(model, new_table_name)
 | 
				
			||||||
 | 
					    > migrator.add_index(model, *col_names, unique=False)
 | 
				
			||||||
 | 
					    > migrator.add_not_null(model, *field_names)
 | 
				
			||||||
 | 
					    > migrator.add_default(model, field_name, default)
 | 
				
			||||||
 | 
					    > migrator.add_constraint(model, name, sql)
 | 
				
			||||||
 | 
					    > migrator.drop_index(model, *col_names)
 | 
				
			||||||
 | 
					    > migrator.drop_not_null(model, *field_names)
 | 
				
			||||||
 | 
					    > migrator.drop_constraints(model, *constraints)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from contextlib import suppress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import peewee as pw
 | 
				
			||||||
 | 
					from peewee_migrate import Migrator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					with suppress(ImportError):
 | 
				
			||||||
 | 
					    import playhouse.postgres_ext as pw_pext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def migrate(migrator: Migrator, database: pw.Database, *, fake=False):
 | 
				
			||||||
 | 
					    """Write your migrations here."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Adding fields settings to the 'user' table
 | 
				
			||||||
 | 
					    migrator.add_fields("user", settings=pw.TextField(null=True))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def rollback(migrator: Migrator, database: pw.Database, *, fake=False):
 | 
				
			||||||
 | 
					    """Write your rollback migrations here."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Remove the settings field
 | 
				
			||||||
 | 
					    migrator.remove_fields("user", "settings")
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
from pydantic import BaseModel
 | 
					from pydantic import BaseModel, ConfigDict
 | 
				
			||||||
from peewee import *
 | 
					from peewee import *
 | 
				
			||||||
from playhouse.shortcuts import model_to_dict
 | 
					from playhouse.shortcuts import model_to_dict
 | 
				
			||||||
from typing import List, Union, Optional
 | 
					from typing import List, Union, Optional
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
from utils.misc import get_gravatar_url
 | 
					from utils.misc import get_gravatar_url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from apps.webui.internal.db import DB
 | 
					from apps.webui.internal.db import DB, JSONField
 | 
				
			||||||
from apps.webui.models.chats import Chats
 | 
					from apps.webui.models.chats import Chats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
####################
 | 
					####################
 | 
				
			||||||
| 
						 | 
					@ -25,11 +25,18 @@ class User(Model):
 | 
				
			||||||
    created_at = BigIntegerField()
 | 
					    created_at = BigIntegerField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    api_key = CharField(null=True, unique=True)
 | 
					    api_key = CharField(null=True, unique=True)
 | 
				
			||||||
 | 
					    settings = JSONField(null=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        database = DB
 | 
					        database = DB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserSettings(BaseModel):
 | 
				
			||||||
 | 
					    ui: Optional[dict] = {}
 | 
				
			||||||
 | 
					    model_config = ConfigDict(extra="allow")
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserModel(BaseModel):
 | 
					class UserModel(BaseModel):
 | 
				
			||||||
    id: str
 | 
					    id: str
 | 
				
			||||||
    name: str
 | 
					    name: str
 | 
				
			||||||
| 
						 | 
					@ -42,6 +49,7 @@ class UserModel(BaseModel):
 | 
				
			||||||
    created_at: int  # timestamp in epoch
 | 
					    created_at: int  # timestamp in epoch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    api_key: Optional[str] = None
 | 
					    api_key: Optional[str] = None
 | 
				
			||||||
 | 
					    settings: Optional[UserSettings] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
####################
 | 
					####################
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,13 @@ import time
 | 
				
			||||||
import uuid
 | 
					import uuid
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from apps.webui.models.users import UserModel, UserUpdateForm, UserRoleUpdateForm, Users
 | 
					from apps.webui.models.users import (
 | 
				
			||||||
 | 
					    UserModel,
 | 
				
			||||||
 | 
					    UserUpdateForm,
 | 
				
			||||||
 | 
					    UserRoleUpdateForm,
 | 
				
			||||||
 | 
					    UserSettings,
 | 
				
			||||||
 | 
					    Users,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
from apps.webui.models.auths import Auths
 | 
					from apps.webui.models.auths import Auths
 | 
				
			||||||
from apps.webui.models.chats import Chats
 | 
					from apps.webui.models.chats import Chats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,6 +74,42 @@ async def update_user_role(form_data: UserRoleUpdateForm, user=Depends(get_admin
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					############################
 | 
				
			||||||
 | 
					# GetUserSettingsBySessionUser
 | 
				
			||||||
 | 
					############################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@router.get("/user/settings", response_model=Optional[UserSettings])
 | 
				
			||||||
 | 
					async def get_user_settings_by_session_user(user=Depends(get_verified_user)):
 | 
				
			||||||
 | 
					    user = Users.get_user_by_id(user.id)
 | 
				
			||||||
 | 
					    if user:
 | 
				
			||||||
 | 
					        return user.settings
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        raise HTTPException(
 | 
				
			||||||
 | 
					            status_code=status.HTTP_400_BAD_REQUEST,
 | 
				
			||||||
 | 
					            detail=ERROR_MESSAGES.USER_NOT_FOUND,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					############################
 | 
				
			||||||
 | 
					# UpdateUserSettingsBySessionUser
 | 
				
			||||||
 | 
					############################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@router.post("/user/settings/update", response_model=UserSettings)
 | 
				
			||||||
 | 
					async def update_user_settings_by_session_user(
 | 
				
			||||||
 | 
					    form_data: UserSettings, user=Depends(get_verified_user)
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    user = Users.update_user_by_id(user.id, {"settings": form_data.model_dump()})
 | 
				
			||||||
 | 
					    if user:
 | 
				
			||||||
 | 
					        return user.settings
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        raise HTTPException(
 | 
				
			||||||
 | 
					            status_code=status.HTTP_400_BAD_REQUEST,
 | 
				
			||||||
 | 
					            detail=ERROR_MESSAGES.USER_NOT_FOUND,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
############################
 | 
					############################
 | 
				
			||||||
# GetUserById
 | 
					# GetUserById
 | 
				
			||||||
############################
 | 
					############################
 | 
				
			||||||
| 
						 | 
					@ -81,6 +123,8 @@ class UserResponse(BaseModel):
 | 
				
			||||||
@router.get("/{user_id}", response_model=UserResponse)
 | 
					@router.get("/{user_id}", response_model=UserResponse)
 | 
				
			||||||
async def get_user_by_id(user_id: str, user=Depends(get_verified_user)):
 | 
					async def get_user_by_id(user_id: str, user=Depends(get_verified_user)):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Check if user_id is a shared chat
 | 
				
			||||||
 | 
					    # If it is, get the user_id from the chat
 | 
				
			||||||
    if user_id.startswith("shared-"):
 | 
					    if user_id.startswith("shared-"):
 | 
				
			||||||
        chat_id = user_id.replace("shared-", "")
 | 
					        chat_id = user_id.replace("shared-", "")
 | 
				
			||||||
        chat = Chats.get_chat_by_id(chat_id)
 | 
					        chat = Chats.get_chat_by_id(chat_id)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,6 +115,62 @@ export const getUsers = async (token: string) => {
 | 
				
			||||||
	return res ? res : [];
 | 
						return res ? res : [];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getUserSettings = async (token: string) => {
 | 
				
			||||||
 | 
						let error = null;
 | 
				
			||||||
 | 
						const res = await fetch(`${WEBUI_API_BASE_URL}/users/user/settings`, {
 | 
				
			||||||
 | 
							method: 'GET',
 | 
				
			||||||
 | 
							headers: {
 | 
				
			||||||
 | 
								'Content-Type': 'application/json',
 | 
				
			||||||
 | 
								Authorization: `Bearer ${token}`
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
							.then(async (res) => {
 | 
				
			||||||
 | 
								if (!res.ok) throw await res.json();
 | 
				
			||||||
 | 
								return res.json();
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							.catch((err) => {
 | 
				
			||||||
 | 
								console.log(err);
 | 
				
			||||||
 | 
								error = err.detail;
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (error) {
 | 
				
			||||||
 | 
							throw error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const updateUserSettings = async (token: string, settings: object) => {
 | 
				
			||||||
 | 
						let error = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const res = await fetch(`${WEBUI_API_BASE_URL}/users/user/settings/update`, {
 | 
				
			||||||
 | 
							method: 'POST',
 | 
				
			||||||
 | 
							headers: {
 | 
				
			||||||
 | 
								'Content-Type': 'application/json',
 | 
				
			||||||
 | 
								Authorization: `Bearer ${token}`
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							body: JSON.stringify({
 | 
				
			||||||
 | 
								...settings
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
							.then(async (res) => {
 | 
				
			||||||
 | 
								if (!res.ok) throw await res.json();
 | 
				
			||||||
 | 
								return res.json();
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							.catch((err) => {
 | 
				
			||||||
 | 
								console.log(err);
 | 
				
			||||||
 | 
								error = err.detail;
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (error) {
 | 
				
			||||||
 | 
							throw error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getUserById = async (token: string, userId: string) => {
 | 
					export const getUserById = async (token: string, userId: string) => {
 | 
				
			||||||
	let error = null;
 | 
						let error = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,7 @@
 | 
				
			||||||
	import type { Writable } from 'svelte/store';
 | 
						import type { Writable } from 'svelte/store';
 | 
				
			||||||
	import type { i18n as i18nType } from 'i18next';
 | 
						import type { i18n as i18nType } from 'i18next';
 | 
				
			||||||
	import Banner from '../common/Banner.svelte';
 | 
						import Banner from '../common/Banner.svelte';
 | 
				
			||||||
 | 
						import { getUserSettings } from '$lib/apis/users';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const i18n: Writable<i18nType> = getContext('i18n');
 | 
						const i18n: Writable<i18nType> = getContext('i18n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -154,10 +155,13 @@
 | 
				
			||||||
			$models.map((m) => m.id).includes(modelId) ? modelId : ''
 | 
								$models.map((m) => m.id).includes(modelId) ? modelId : ''
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let _settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
 | 
							const userSettings = await getUserSettings(localStorage.token);
 | 
				
			||||||
		settings.set({
 | 
					
 | 
				
			||||||
			..._settings
 | 
							if (userSettings) {
 | 
				
			||||||
		});
 | 
								settings.set(userSettings.ui);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const chatInput = document.getElementById('chat-textarea');
 | 
							const chatInput = document.getElementById('chat-textarea');
 | 
				
			||||||
		setTimeout(() => chatInput?.focus(), 0);
 | 
							setTimeout(() => chatInput?.focus(), 0);
 | 
				
			||||||
| 
						 | 
					@ -187,11 +191,18 @@
 | 
				
			||||||
						: convertMessagesToHistory(chatContent.messages);
 | 
											: convertMessagesToHistory(chatContent.messages);
 | 
				
			||||||
				title = chatContent.title;
 | 
									title = chatContent.title;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				let _settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
 | 
									const userSettings = await getUserSettings(localStorage.token);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (userSettings) {
 | 
				
			||||||
 | 
										await settings.set(userSettings.ui);
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				await settings.set({
 | 
									await settings.set({
 | 
				
			||||||
					..._settings,
 | 
										...$settings,
 | 
				
			||||||
					system: chatContent.system ?? _settings.system,
 | 
										system: chatContent.system ?? $settings.system,
 | 
				
			||||||
					params: chatContent.options ?? _settings.params
 | 
										params: chatContent.options ?? $settings.params
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
				autoScroll = true;
 | 
									autoScroll = true;
 | 
				
			||||||
				await tick();
 | 
									await tick();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,13 @@
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
	import { Collapsible } from 'bits-ui';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	import { setDefaultModels } from '$lib/apis/configs';
 | 
					 | 
				
			||||||
	import { models, showSettings, settings, user, mobile } from '$lib/stores';
 | 
						import { models, showSettings, settings, user, mobile } from '$lib/stores';
 | 
				
			||||||
	import { onMount, tick, getContext } from 'svelte';
 | 
						import { onMount, tick, getContext } from 'svelte';
 | 
				
			||||||
	import { toast } from 'svelte-sonner';
 | 
						import { toast } from 'svelte-sonner';
 | 
				
			||||||
	import Selector from './ModelSelector/Selector.svelte';
 | 
						import Selector from './ModelSelector/Selector.svelte';
 | 
				
			||||||
	import Tooltip from '../common/Tooltip.svelte';
 | 
						import Tooltip from '../common/Tooltip.svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						import { setDefaultModels } from '$lib/apis/configs';
 | 
				
			||||||
 | 
						import { updateUserSettings } from '$lib/apis/users';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const i18n = getContext('i18n');
 | 
						const i18n = getContext('i18n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	export let selectedModels = [''];
 | 
						export let selectedModels = [''];
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,9 @@
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		settings.set({ ...$settings, models: selectedModels });
 | 
							settings.set({ ...$settings, models: selectedModels });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		localStorage.setItem('settings', JSON.stringify($settings));
 | 
							localStorage.setItem('settings', JSON.stringify($settings));
 | 
				
			||||||
 | 
							await updateUserSettings(localStorage.token, { ui: $settings });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ($user.role === 'admin') {
 | 
							if ($user.role === 'admin') {
 | 
				
			||||||
			console.log('setting default models globally');
 | 
								console.log('setting default models globally');
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
	import { getAudioConfig, updateAudioConfig } from '$lib/apis/audio';
 | 
						import { getAudioConfig, updateAudioConfig } from '$lib/apis/audio';
 | 
				
			||||||
	import { user } from '$lib/stores';
 | 
						import { user, settings } from '$lib/stores';
 | 
				
			||||||
	import { createEventDispatcher, onMount, getContext } from 'svelte';
 | 
						import { createEventDispatcher, onMount, getContext } from 'svelte';
 | 
				
			||||||
	import { toast } from 'svelte-sonner';
 | 
						import { toast } from 'svelte-sonner';
 | 
				
			||||||
	const dispatch = createEventDispatcher();
 | 
						const dispatch = createEventDispatcher();
 | 
				
			||||||
| 
						 | 
					@ -99,16 +99,14 @@
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	onMount(async () => {
 | 
						onMount(async () => {
 | 
				
			||||||
		let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
 | 
							conversationMode = $settings.conversationMode ?? false;
 | 
				
			||||||
 | 
							speechAutoSend = $settings.speechAutoSend ?? false;
 | 
				
			||||||
 | 
							responseAutoPlayback = $settings.responseAutoPlayback ?? false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		conversationMode = settings.conversationMode ?? false;
 | 
							STTEngine = $settings?.audio?.STTEngine ?? '';
 | 
				
			||||||
		speechAutoSend = settings.speechAutoSend ?? false;
 | 
							TTSEngine = $settings?.audio?.TTSEngine ?? '';
 | 
				
			||||||
		responseAutoPlayback = settings.responseAutoPlayback ?? false;
 | 
							speaker = $settings?.audio?.speaker ?? '';
 | 
				
			||||||
 | 
							model = $settings?.audio?.model ?? '';
 | 
				
			||||||
		STTEngine = settings?.audio?.STTEngine ?? '';
 | 
					 | 
				
			||||||
		TTSEngine = settings?.audio?.TTSEngine ?? '';
 | 
					 | 
				
			||||||
		speaker = settings?.audio?.speaker ?? '';
 | 
					 | 
				
			||||||
		model = settings?.audio?.model ?? '';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (TTSEngine === 'openai') {
 | 
							if (TTSEngine === 'openai') {
 | 
				
			||||||
			getOpenAIVoices();
 | 
								getOpenAIVoices();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
	import fileSaver from 'file-saver';
 | 
						import fileSaver from 'file-saver';
 | 
				
			||||||
	const { saveAs } = fileSaver;
 | 
						const { saveAs } = fileSaver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	import { chats, user, config } from '$lib/stores';
 | 
						import { chats, user, settings } from '$lib/stores';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	import {
 | 
						import {
 | 
				
			||||||
		archiveAllChats,
 | 
							archiveAllChats,
 | 
				
			||||||
| 
						 | 
					@ -99,9 +99,7 @@
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	onMount(async () => {
 | 
						onMount(async () => {
 | 
				
			||||||
		let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
 | 
							saveChatHistory = $settings.saveChatHistory ?? true;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		saveChatHistory = settings.saveChatHistory ?? true;
 | 
					 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
	import { getLanguages } from '$lib/i18n';
 | 
						import { getLanguages } from '$lib/i18n';
 | 
				
			||||||
	const dispatch = createEventDispatcher();
 | 
						const dispatch = createEventDispatcher();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	import { models, user, theme } from '$lib/stores';
 | 
						import { models, settings, theme } from '$lib/stores';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const i18n = getContext('i18n');
 | 
						const i18n = getContext('i18n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,23 +71,22 @@
 | 
				
			||||||
	onMount(async () => {
 | 
						onMount(async () => {
 | 
				
			||||||
		selectedTheme = localStorage.theme ?? 'system';
 | 
							selectedTheme = localStorage.theme ?? 'system';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
 | 
					 | 
				
			||||||
		languages = await getLanguages();
 | 
							languages = await getLanguages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		notificationEnabled = settings.notificationEnabled ?? false;
 | 
							notificationEnabled = $settings.notificationEnabled ?? false;
 | 
				
			||||||
		system = settings.system ?? '';
 | 
							system = $settings.system ?? '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		requestFormat = settings.requestFormat ?? '';
 | 
							requestFormat = $settings.requestFormat ?? '';
 | 
				
			||||||
		keepAlive = settings.keepAlive ?? null;
 | 
							keepAlive = $settings.keepAlive ?? null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		params.seed = settings.seed ?? 0;
 | 
							params.seed = $settings.seed ?? 0;
 | 
				
			||||||
		params.temperature = settings.temperature ?? '';
 | 
							params.temperature = $settings.temperature ?? '';
 | 
				
			||||||
		params.frequency_penalty = settings.frequency_penalty ?? '';
 | 
							params.frequency_penalty = $settings.frequency_penalty ?? '';
 | 
				
			||||||
		params.top_k = settings.top_k ?? '';
 | 
							params.top_k = $settings.top_k ?? '';
 | 
				
			||||||
		params.top_p = settings.top_p ?? '';
 | 
							params.top_p = $settings.top_p ?? '';
 | 
				
			||||||
		params.num_ctx = settings.num_ctx ?? '';
 | 
							params.num_ctx = $settings.num_ctx ?? '';
 | 
				
			||||||
		params = { ...params, ...settings.params };
 | 
							params = { ...params, ...$settings.params };
 | 
				
			||||||
		params.stop = settings?.params?.stop ? (settings?.params?.stop ?? []).join(',') : null;
 | 
							params.stop = $settings?.params?.stop ? ($settings?.params?.stop ?? []).join(',') : null;
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const applyTheme = (_theme: string) => {
 | 
						const applyTheme = (_theme: string) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,23 +104,18 @@
 | 
				
			||||||
			promptSuggestions = $config?.default_prompt_suggestions;
 | 
								promptSuggestions = $config?.default_prompt_suggestions;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
 | 
							titleAutoGenerate = $settings?.title?.auto ?? true;
 | 
				
			||||||
 | 
							titleAutoGenerateModel = $settings?.title?.model ?? '';
 | 
				
			||||||
		titleAutoGenerate = settings?.title?.auto ?? true;
 | 
							titleAutoGenerateModelExternal = $settings?.title?.modelExternal ?? '';
 | 
				
			||||||
		titleAutoGenerateModel = settings?.title?.model ?? '';
 | 
					 | 
				
			||||||
		titleAutoGenerateModelExternal = settings?.title?.modelExternal ?? '';
 | 
					 | 
				
			||||||
		titleGenerationPrompt =
 | 
							titleGenerationPrompt =
 | 
				
			||||||
			settings?.title?.prompt ??
 | 
								$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}}`;
 | 
				
			||||||
				"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':"
 | 
							responseAutoCopy = $settings.responseAutoCopy ?? false;
 | 
				
			||||||
			) + ' {{prompt}}';
 | 
							showUsername = $settings.showUsername ?? false;
 | 
				
			||||||
 | 
							chatBubble = $settings.chatBubble ?? true;
 | 
				
			||||||
		responseAutoCopy = settings.responseAutoCopy ?? false;
 | 
							fullScreenMode = $settings.fullScreenMode ?? false;
 | 
				
			||||||
		showUsername = settings.showUsername ?? false;
 | 
							splitLargeChunks = $settings.splitLargeChunks ?? false;
 | 
				
			||||||
		chatBubble = settings.chatBubble ?? true;
 | 
							chatDirection = $settings.chatDirection ?? 'LTR';
 | 
				
			||||||
		fullScreenMode = settings.fullScreenMode ?? false;
 | 
					 | 
				
			||||||
		splitLargeChunks = settings.splitLargeChunks ?? false;
 | 
					 | 
				
			||||||
		chatDirection = settings.chatDirection ?? 'LTR';
 | 
					 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,8 +19,7 @@
 | 
				
			||||||
	let enableMemory = false;
 | 
						let enableMemory = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	onMount(async () => {
 | 
						onMount(async () => {
 | 
				
			||||||
		let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
 | 
							enableMemory = $settings?.memory ?? false;
 | 
				
			||||||
		enableMemory = settings?.memory ?? false;
 | 
					 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@
 | 
				
			||||||
	import Images from './Settings/Images.svelte';
 | 
						import Images from './Settings/Images.svelte';
 | 
				
			||||||
	import User from '../icons/User.svelte';
 | 
						import User from '../icons/User.svelte';
 | 
				
			||||||
	import Personalization from './Settings/Personalization.svelte';
 | 
						import Personalization from './Settings/Personalization.svelte';
 | 
				
			||||||
 | 
						import { updateUserSettings } from '$lib/apis/users';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const i18n = getContext('i18n');
 | 
						const i18n = getContext('i18n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +27,9 @@
 | 
				
			||||||
		console.log(updated);
 | 
							console.log(updated);
 | 
				
			||||||
		await settings.set({ ...$settings, ...updated });
 | 
							await settings.set({ ...$settings, ...updated });
 | 
				
			||||||
		await models.set(await getModels());
 | 
							await models.set(await getModels());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		localStorage.setItem('settings', JSON.stringify($settings));
 | 
							localStorage.setItem('settings', JSON.stringify($settings));
 | 
				
			||||||
 | 
							await updateUserSettings(localStorage.token, { ui: $settings });
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const getModels = async () => {
 | 
						const getModels = async () => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,7 @@
 | 
				
			||||||
	import ArchiveBox from '../icons/ArchiveBox.svelte';
 | 
						import ArchiveBox from '../icons/ArchiveBox.svelte';
 | 
				
			||||||
	import ArchivedChatsModal from './Sidebar/ArchivedChatsModal.svelte';
 | 
						import ArchivedChatsModal from './Sidebar/ArchivedChatsModal.svelte';
 | 
				
			||||||
	import UserMenu from './Sidebar/UserMenu.svelte';
 | 
						import UserMenu from './Sidebar/UserMenu.svelte';
 | 
				
			||||||
 | 
						import { updateUserSettings } from '$lib/apis/users';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const BREAKPOINT = 768;
 | 
						const BREAKPOINT = 768;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,6 +185,8 @@
 | 
				
			||||||
	const saveSettings = async (updated) => {
 | 
						const saveSettings = async (updated) => {
 | 
				
			||||||
		await settings.set({ ...$settings, ...updated });
 | 
							await settings.set({ ...$settings, ...updated });
 | 
				
			||||||
		localStorage.setItem('settings', JSON.stringify($settings));
 | 
							localStorage.setItem('settings', JSON.stringify($settings));
 | 
				
			||||||
 | 
							await updateUserSettings(localStorage.token, { ui: $settings });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		location.href = '/';
 | 
							location.href = '/';
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,7 @@
 | 
				
			||||||
	import ChangelogModal from '$lib/components/ChangelogModal.svelte';
 | 
						import ChangelogModal from '$lib/components/ChangelogModal.svelte';
 | 
				
			||||||
	import Tooltip from '$lib/components/common/Tooltip.svelte';
 | 
						import Tooltip from '$lib/components/common/Tooltip.svelte';
 | 
				
			||||||
	import { getBanners } from '$lib/apis/configs';
 | 
						import { getBanners } from '$lib/apis/configs';
 | 
				
			||||||
 | 
						import { getUserSettings } from '$lib/apis/users';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const i18n = getContext('i18n');
 | 
						const i18n = getContext('i18n');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +73,13 @@
 | 
				
			||||||
				// IndexedDB Not Found
 | 
									// IndexedDB Not Found
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
 | 
								const userSettings = await getUserSettings(localStorage.token);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (userSettings) {
 | 
				
			||||||
 | 
									await settings.set(userSettings.ui);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									await settings.set(JSON.parse(localStorage.getItem('settings') ?? '{}'));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			await Promise.all([
 | 
								await Promise.all([
 | 
				
			||||||
				(async () => {
 | 
									(async () => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,12 +98,6 @@
 | 
				
			||||||
						: convertMessagesToHistory(chatContent.messages);
 | 
											: convertMessagesToHistory(chatContent.messages);
 | 
				
			||||||
				title = chatContent.title;
 | 
									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;
 | 
									autoScroll = true;
 | 
				
			||||||
				await tick();
 | 
									await tick();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue