forked from open-webui/open-webui
Merge branch 'main' into rag
This commit is contained in:
commit
438942d64e
7 changed files with 207 additions and 64 deletions
|
@ -22,7 +22,6 @@ ARG OLLAMA_API_BASE_URL='/ollama/api'
|
|||
|
||||
ENV ENV=prod
|
||||
ENV OLLAMA_API_BASE_URL $OLLAMA_API_BASE_URL
|
||||
ENV WEBUI_AUTH ""
|
||||
ENV WEBUI_JWT_SECRET_KEY "SECRET_KEY"
|
||||
|
||||
WORKDIR /app
|
||||
|
|
|
@ -8,6 +8,8 @@ app = FastAPI()
|
|||
|
||||
origins = ["*"]
|
||||
|
||||
app.state.ENABLE_SIGNUP = True
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from fastapi import Response
|
||||
from fastapi import Response, Request
|
||||
from fastapi import Depends, FastAPI, HTTPException, status
|
||||
from datetime import datetime, timedelta
|
||||
from typing import List, Union
|
||||
|
@ -93,31 +93,62 @@ async def signin(form_data: SigninForm):
|
|||
|
||||
|
||||
@router.post("/signup", response_model=SigninResponse)
|
||||
async def signup(form_data: SignupForm):
|
||||
if not Users.get_user_by_email(form_data.email.lower()):
|
||||
try:
|
||||
role = "admin" if Users.get_num_users() == 0 else "pending"
|
||||
hashed = get_password_hash(form_data.password)
|
||||
user = Auths.insert_new_auth(
|
||||
form_data.email.lower(), hashed, form_data.name, role
|
||||
)
|
||||
async def signup(request: Request, form_data: SignupForm):
|
||||
if request.app.state.ENABLE_SIGNUP:
|
||||
if not Users.get_user_by_email(form_data.email.lower()):
|
||||
try:
|
||||
role = "admin" if Users.get_num_users() == 0 else "pending"
|
||||
hashed = get_password_hash(form_data.password)
|
||||
user = Auths.insert_new_auth(
|
||||
form_data.email.lower(), hashed, form_data.name, role
|
||||
)
|
||||
|
||||
if user:
|
||||
token = create_token(data={"email": user.email})
|
||||
# response.set_cookie(key='token', value=token, httponly=True)
|
||||
if user:
|
||||
token = create_token(data={"email": user.email})
|
||||
# response.set_cookie(key='token', value=token, httponly=True)
|
||||
|
||||
return {
|
||||
"token": token,
|
||||
"token_type": "Bearer",
|
||||
"id": user.id,
|
||||
"email": user.email,
|
||||
"name": user.name,
|
||||
"role": user.role,
|
||||
"profile_image_url": user.profile_image_url,
|
||||
}
|
||||
else:
|
||||
raise HTTPException(500, detail=ERROR_MESSAGES.CREATE_USER_ERROR)
|
||||
except Exception as err:
|
||||
raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
|
||||
return {
|
||||
"token": token,
|
||||
"token_type": "Bearer",
|
||||
"id": user.id,
|
||||
"email": user.email,
|
||||
"name": user.name,
|
||||
"role": user.role,
|
||||
"profile_image_url": user.profile_image_url,
|
||||
}
|
||||
else:
|
||||
raise HTTPException(500, detail=ERROR_MESSAGES.CREATE_USER_ERROR)
|
||||
except Exception as err:
|
||||
raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
|
||||
else:
|
||||
raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN)
|
||||
else:
|
||||
raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN)
|
||||
raise HTTPException(400, detail=ERROR_MESSAGES.ACCESS_PROHIBITED)
|
||||
|
||||
|
||||
############################
|
||||
# ToggleSignUp
|
||||
############################
|
||||
|
||||
|
||||
@router.get("/signup/enabled", response_model=bool)
|
||||
async def get_sign_up_status(request: Request, user=Depends(get_current_user)):
|
||||
if user.role == "admin":
|
||||
return request.app.state.ENABLE_SIGNUP
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/signup/enabled/toggle", response_model=bool)
|
||||
async def toggle_sign_up(request: Request, user=Depends(get_current_user)):
|
||||
if user.role == "admin":
|
||||
request.app.state.ENABLE_SIGNUP = not request.app.state.ENABLE_SIGNUP
|
||||
return request.app.state.ENABLE_SIGNUP
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
|
|
|
@ -15,6 +15,7 @@ from apps.web.models.auths import Auths
|
|||
from utils.utils import get_current_user
|
||||
from constants import ERROR_MESSAGES
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
############################
|
||||
|
|
|
@ -119,3 +119,57 @@ export const updateUserPassword = async (token: string, password: string, newPas
|
|||
|
||||
return res;
|
||||
};
|
||||
|
||||
export const getSignUpEnabledStatus = async (token: string) => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${WEBUI_API_BASE_URL}/auths/signup/enabled`, {
|
||||
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 toggleSignUpEnabledStatus = async (token: string) => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${WEBUI_API_BASE_URL}/auths/signup/enabled/toggle`, {
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -215,42 +215,44 @@
|
|||
{#if messages.length == 0}
|
||||
<Placeholder models={selectedModels} modelfiles={selectedModelfiles} />
|
||||
{:else}
|
||||
{#each messages as message, messageIdx}
|
||||
<div class=" w-full">
|
||||
<div class="flex justify-between px-5 mb-3 max-w-3xl mx-auto rounded-lg group">
|
||||
{#if message.role === 'user'}
|
||||
<UserMessage
|
||||
user={$user}
|
||||
{message}
|
||||
siblings={message.parentId !== null
|
||||
? history.messages[message.parentId]?.childrenIds ?? []
|
||||
: Object.values(history.messages)
|
||||
.filter((message) => message.parentId === null)
|
||||
.map((message) => message.id) ?? []}
|
||||
{confirmEditMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{copyToClipboard}
|
||||
/>
|
||||
{:else}
|
||||
<ResponseMessage
|
||||
{message}
|
||||
modelfiles={selectedModelfiles}
|
||||
siblings={history.messages[message.parentId]?.childrenIds ?? []}
|
||||
isLastMessage={messageIdx + 1 === messages.length}
|
||||
{confirmEditResponseMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{rateMessage}
|
||||
{copyToClipboard}
|
||||
{regenerateResponse}
|
||||
/>
|
||||
{/if}
|
||||
{#key chatId}
|
||||
{#each messages as message, messageIdx}
|
||||
<div class=" w-full">
|
||||
<div class="flex justify-between px-5 mb-3 max-w-3xl mx-auto rounded-lg group">
|
||||
{#if message.role === 'user'}
|
||||
<UserMessage
|
||||
user={$user}
|
||||
{message}
|
||||
siblings={message.parentId !== null
|
||||
? history.messages[message.parentId]?.childrenIds ?? []
|
||||
: Object.values(history.messages)
|
||||
.filter((message) => message.parentId === null)
|
||||
.map((message) => message.id) ?? []}
|
||||
{confirmEditMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{copyToClipboard}
|
||||
/>
|
||||
{:else}
|
||||
<ResponseMessage
|
||||
{message}
|
||||
modelfiles={selectedModelfiles}
|
||||
siblings={history.messages[message.parentId]?.childrenIds ?? []}
|
||||
isLastMessage={messageIdx + 1 === messages.length}
|
||||
{confirmEditResponseMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{rateMessage}
|
||||
{copyToClipboard}
|
||||
{regenerateResponse}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
|
||||
{#if bottomPadding}
|
||||
<div class=" mb-10" />
|
||||
{/if}
|
||||
{#if bottomPadding}
|
||||
<div class=" mb-10" />
|
||||
{/if}
|
||||
{/key}
|
||||
{/if}
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
import toast from 'svelte-french-toast';
|
||||
|
||||
import { updateUserRole, getUsers, deleteUserById } from '$lib/apis/users';
|
||||
import { getSignUpEnabledStatus, toggleSignUpEnabledStatus } from '$lib/apis/auths';
|
||||
|
||||
let loaded = false;
|
||||
let users = [];
|
||||
|
||||
let signUpEnabled = true;
|
||||
|
||||
const updateRoleHandler = async (id, role) => {
|
||||
const res = await updateUserRole(localStorage.token, id, role).catch((error) => {
|
||||
toast.error(error);
|
||||
|
@ -32,11 +35,17 @@
|
|||
}
|
||||
};
|
||||
|
||||
const toggleSignUpEnabled = async () => {
|
||||
signUpEnabled = await toggleSignUpEnabledStatus(localStorage.token);
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
if ($user?.role !== 'admin') {
|
||||
await goto('/');
|
||||
} else {
|
||||
users = await getUsers(localStorage.token);
|
||||
|
||||
signUpEnabled = await getSignUpEnabledStatus(localStorage.token);
|
||||
}
|
||||
loaded = true;
|
||||
});
|
||||
|
@ -49,7 +58,52 @@
|
|||
<div class="w-full max-w-3xl px-10 md:px-16 min-h-screen flex flex-col">
|
||||
<div class="py-10 w-full">
|
||||
<div class=" flex flex-col justify-center">
|
||||
<div class=" text-2xl font-semibold">Users ({users.length})</div>
|
||||
<div class=" flex justify-between items-center">
|
||||
<div class=" text-2xl font-semibold">Users ({users.length})</div>
|
||||
<div>
|
||||
<button
|
||||
class="flex items-center space-x-1 border border-gray-200 dark:border-gray-600 px-3 py-1 rounded-lg"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
toggleSignUpEnabled();
|
||||
}}
|
||||
>
|
||||
{#if signUpEnabled}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
d="M11.5 1A3.5 3.5 0 0 0 8 4.5V7H2.5A1.5 1.5 0 0 0 1 8.5v5A1.5 1.5 0 0 0 2.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 9.5 7V4.5a2 2 0 1 1 4 0v1.75a.75.75 0 0 0 1.5 0V4.5A3.5 3.5 0 0 0 11.5 1Z"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<div class=" text-xs">
|
||||
New Sign Up <span class=" font-semibold">Enabled</span>
|
||||
</div>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7A1.5 1.5 0 0 0 3 8.5v5A1.5 1.5 0 0 0 4.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 11.5 7V4.5A3.5 3.5 0 0 0 8 1Zm2 6V4.5a2 2 0 1 0-4 0V7h4Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<div class=" text-xs">
|
||||
New Sign Up <span class=" font-semibold">Disabled</span>
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class=" text-gray-500 text-xs font-medium mt-1">
|
||||
Click on the user role cell in the table to change a user's role.
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue