Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
open-webui
Commits
438942d6
Unverified
Commit
438942d6
authored
Jan 01, 2024
by
Timothy Jaeryang Baek
Committed by
GitHub
Jan 01, 2024
Browse files
Merge branch 'main' into rag
parents
ee155937
9937b5e4
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
209 additions
and
66 deletions
+209
-66
Dockerfile
Dockerfile
+0
-1
backend/apps/web/main.py
backend/apps/web/main.py
+2
-0
backend/apps/web/routers/auths.py
backend/apps/web/routers/auths.py
+59
-28
backend/apps/web/routers/users.py
backend/apps/web/routers/users.py
+1
-0
src/lib/apis/auths/index.ts
src/lib/apis/auths/index.ts
+54
-0
src/lib/components/chat/Messages.svelte
src/lib/components/chat/Messages.svelte
+38
-36
src/routes/(app)/admin/+page.svelte
src/routes/(app)/admin/+page.svelte
+55
-1
No files found.
Dockerfile
View file @
438942d6
...
...
@@ -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
...
...
backend/apps/web/main.py
View file @
438942d6
...
...
@@ -8,6 +8,8 @@ app = FastAPI()
origins
=
[
"*"
]
app
.
state
.
ENABLE_SIGNUP
=
True
app
.
add_middleware
(
CORSMiddleware
,
allow_origins
=
origins
,
...
...
backend/apps/web/routers/auths.py
View file @
438942d6
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
)
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
))
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)
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
.
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
(
400
,
detail
=
ERROR_MESSAGES
.
EMAIL_TAKEN
)
raise
HTTPException
(
status_code
=
status
.
HTTP_403_FORBIDDEN
,
detail
=
ERROR_MESSAGES
.
ACCESS_PROHIBITED
,
)
backend/apps/web/routers/users.py
View file @
438942d6
...
...
@@ -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
()
############################
...
...
src/lib/apis/auths/index.ts
View file @
438942d6
...
...
@@ -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
;
};
src/lib/components/chat/Messages.svelte
View file @
438942d6
...
...
@@ -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}
src/routes/(app)/admin/+page.svelte
View file @
438942d6
...
...
@@ -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>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment