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
e10d029b
Commit
e10d029b
authored
May 19, 2024
by
Robin Kroonen
Browse files
Merge branch 'dev' of
https://github.com/kroonen/open-webui
into dev
parent
867c179e
Changes
65
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
414 additions
and
201 deletions
+414
-201
Dockerfile
Dockerfile
+29
-28
backend/main.py
backend/main.py
+5
-0
cypress/e2e/chat.cy.ts
cypress/e2e/chat.cy.ts
+33
-0
cypress/e2e/settings.cy.ts
cypress/e2e/settings.cy.ts
+2
-6
src/app.css
src/app.css
+11
-0
src/lib/components/admin/AddUserModal.svelte
src/lib/components/admin/AddUserModal.svelte
+5
-2
src/lib/components/admin/Settings/General.svelte
src/lib/components/admin/Settings/General.svelte
+2
-2
src/lib/components/chat/MessageInput.svelte
src/lib/components/chat/MessageInput.svelte
+4
-4
src/lib/components/chat/Messages/ResponseMessage.svelte
src/lib/components/chat/Messages/ResponseMessage.svelte
+87
-87
src/lib/components/chat/Messages/UserMessage.svelte
src/lib/components/chat/Messages/UserMessage.svelte
+154
-57
src/lib/components/chat/Settings/Account.svelte
src/lib/components/chat/Settings/Account.svelte
+1
-1
src/lib/components/chat/Settings/Advanced.svelte
src/lib/components/chat/Settings/Advanced.svelte
+1
-1
src/lib/components/chat/Settings/Advanced/AdvancedParams.svelte
...b/components/chat/Settings/Advanced/AdvancedParams.svelte
+2
-2
src/lib/components/chat/Settings/Audio.svelte
src/lib/components/chat/Settings/Audio.svelte
+2
-2
src/lib/components/chat/Settings/Connections.svelte
src/lib/components/chat/Settings/Connections.svelte
+1
-1
src/lib/components/chat/Settings/General.svelte
src/lib/components/chat/Settings/General.svelte
+2
-2
src/lib/components/chat/Settings/Interface.svelte
src/lib/components/chat/Settings/Interface.svelte
+29
-2
src/lib/components/chat/SettingsModal.svelte
src/lib/components/chat/SettingsModal.svelte
+27
-1
src/lib/components/chat/ShareChatModal.svelte
src/lib/components/chat/ShareChatModal.svelte
+15
-1
src/lib/components/common/Modal.svelte
src/lib/components/common/Modal.svelte
+2
-2
No files found.
Dockerfile
View file @
e10d029b
...
@@ -80,25 +80,25 @@ RUN mkdir -p $HOME/.cache/chroma
...
@@ -80,25 +80,25 @@ RUN mkdir -p $HOME/.cache/chroma
RUN
echo
-n
00000000-0000-0000-0000-000000000000
>
$HOME
/.cache/chroma/telemetry_user_id
RUN
echo
-n
00000000-0000-0000-0000-000000000000
>
$HOME
/.cache/chroma/telemetry_user_id
RUN if
[
"
$USE_OLLAMA
"
=
"true"
]
;
then
\
RUN if
[
"
$USE_OLLAMA
"
=
"true"
]
;
then
\
apt-get update
&&
\
apt-get update
&&
\
# Install pandoc and netcat
# Install pandoc and netcat
apt-get install -y --no-install-recommends pandoc netcat-openbsd curl && \
apt-get install -y --no-install-recommends pandoc netcat-openbsd curl && \
# for RAG OCR
# for RAG OCR
apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \
apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \
# install helper tools
# install helper tools
apt-get install -y --no-install-recommends curl && \
apt-get install -y --no-install-recommends curl
jq
&& \
# install ollama
# install ollama
curl -fsSL https://ollama.com/install.sh | sh && \
curl -fsSL https://ollama.com/install.sh | sh && \
# cleanup
# cleanup
rm -rf /var/lib/apt/lists/*; \
rm -rf /var/lib/apt/lists/*; \
else \
else \
apt-get update && \
apt-get update && \
# Install pandoc and netcat
# Install pandoc and netcat
apt-get install -y --no-install-recommends pandoc netcat-openbsd curl && \
apt-get install -y --no-install-recommends pandoc netcat-openbsd curl
jq
&& \
# for RAG OCR
# for RAG OCR
apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \
apt-get install -y --no-install-recommends ffmpeg libsm6 libxext6 && \
# cleanup
# cleanup
rm -rf /var/lib/apt/lists/*; \
rm -rf /var/lib/apt/lists/*; \
fi
fi
# install python dependencies
# install python dependencies
...
@@ -106,16 +106,16 @@ COPY ./backend/requirements.txt ./requirements.txt
...
@@ -106,16 +106,16 @@ COPY ./backend/requirements.txt ./requirements.txt
RUN
pip3
install
uv
&&
\
RUN
pip3
install
uv
&&
\
if
[
"
$USE_CUDA
"
=
"true"
]
;
then
\
if
[
"
$USE_CUDA
"
=
"true"
]
;
then
\
# If you use CUDA the whisper and embedding model will be downloaded on first use
# If you use CUDA the whisper and embedding model will be downloaded on first use
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/$USE_CUDA_DOCKER_VER --no-cache-dir && \
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/$USE_CUDA_DOCKER_VER --no-cache-dir && \
uv pip install --system -r requirements.txt --no-cache-dir && \
uv pip install --system -r requirements.txt --no-cache-dir && \
python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \
python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \
python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \
python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \
else \
else \
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu --no-cache-dir && \
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu --no-cache-dir && \
uv pip install --system -r requirements.txt --no-cache-dir && \
uv pip install --system -r requirements.txt --no-cache-dir && \
python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \
python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \
python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \
python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \
fi
fi
...
@@ -134,6 +134,7 @@ COPY ./backend .
...
@@ -134,6 +134,7 @@ COPY ./backend .
EXPOSE
8080
EXPOSE
8080
HEALTHCHECK
CMD curl --fail http://localhost:8080 || exit 1
HEALTHCHECK
CMD curl --silent --fail http://localhost:8080/health | jq -e '.status == true' || exit 1
CMD
[ "bash", "start.sh"]
CMD
[ "bash", "start.sh"]
backend/main.py
View file @
e10d029b
...
@@ -377,6 +377,11 @@ async def get_opensearch_xml():
...
@@ -377,6 +377,11 @@ async def get_opensearch_xml():
return
Response
(
content
=
xml_content
,
media_type
=
"application/xml"
)
return
Response
(
content
=
xml_content
,
media_type
=
"application/xml"
)
@
app
.
get
(
"/health"
)
async
def
healthcheck
():
return
{
"status"
:
True
}
app
.
mount
(
"/static"
,
StaticFiles
(
directory
=
STATIC_DIR
),
name
=
"static"
)
app
.
mount
(
"/static"
,
StaticFiles
(
directory
=
STATIC_DIR
),
name
=
"static"
)
app
.
mount
(
"/cache"
,
StaticFiles
(
directory
=
CACHE_DIR
),
name
=
"cache"
)
app
.
mount
(
"/cache"
,
StaticFiles
(
directory
=
CACHE_DIR
),
name
=
"cache"
)
...
...
cypress/e2e/chat.cy.ts
View file @
e10d029b
...
@@ -42,5 +42,38 @@ describe('Settings', () => {
...
@@ -42,5 +42,38 @@ describe('Settings', () => {
.
find
(
'
div[aria-label="Generation Info"]
'
,
{
timeout
:
120
_000
})
// Generation Info is created after the stop token is received
.
find
(
'
div[aria-label="Generation Info"]
'
,
{
timeout
:
120
_000
})
// Generation Info is created after the stop token is received
.
should
(
'
exist
'
);
.
should
(
'
exist
'
);
});
});
it
(
'
user can share chat
'
,
()
=>
{
// Click on the model selector
cy
.
get
(
'
button[aria-label="Select a model"]
'
).
click
();
// Select the first model
cy
.
get
(
'
button[aria-label="model-item"]
'
).
first
().
click
();
// Type a message
cy
.
get
(
'
#chat-textarea
'
).
type
(
'
Hi, what can you do? A single sentence only please.
'
,
{
force
:
true
});
// Send the message
cy
.
get
(
'
button[type="submit"]
'
).
click
();
// User's message should be visible
cy
.
get
(
'
.chat-user
'
).
should
(
'
exist
'
);
// Wait for the response
cy
.
get
(
'
.chat-assistant
'
,
{
timeout
:
120
_000
})
// .chat-assistant is created after the first token is received
.
find
(
'
div[aria-label="Generation Info"]
'
,
{
timeout
:
120
_000
})
// Generation Info is created after the stop token is received
.
should
(
'
exist
'
);
// spy on requests
const
spy
=
cy
.
spy
();
cy
.
intercept
(
"
GET
"
,
"
/api/v1/chats/*
"
,
spy
);
// Open context menu
cy
.
get
(
'
#chat-context-menu-button
'
).
click
();
// Click share button
cy
.
get
(
'
#chat-share-button
'
).
click
();
// Check if the share dialog is visible
cy
.
get
(
'
#copy-and-share-chat-button
'
).
should
(
'
exist
'
);
cy
.
wrap
({},
{
timeout
:
5000
})
.
should
(()
=>
{
// Check if the request was made twice (once for to replace chat object and once more due to change event)
expect
(
spy
).
to
.
be
.
callCount
(
2
);
});
});
});
});
});
});
cypress/e2e/settings.cy.ts
View file @
e10d029b
...
@@ -15,12 +15,8 @@ describe('Settings', () => {
...
@@ -15,12 +15,8 @@ describe('Settings', () => {
cy
.
loginAdmin
();
cy
.
loginAdmin
();
// Visit the home page
// Visit the home page
cy
.
visit
(
'
/
'
);
cy
.
visit
(
'
/
'
);
// Open the sidebar if it is not already open
// Click on the user menu
cy
.
get
(
'
[aria-label="Open sidebar"]
'
).
then
(()
=>
{
cy
.
get
(
'
button[aria-label="User Menu"]
'
).
click
();
cy
.
get
(
'
button[id="sidebar-toggle-button"]
'
).
click
();
});
// Click on the profile link
cy
.
get
(
'
button
'
).
contains
(
adminUser
.
name
).
click
();
// Click on the settings link
// Click on the settings link
cy
.
get
(
'
button
'
).
contains
(
'
Settings
'
).
click
();
cy
.
get
(
'
button
'
).
contains
(
'
Settings
'
).
click
();
});
});
...
...
src/app.css
View file @
e10d029b
...
@@ -100,3 +100,14 @@ select {
...
@@ -100,3 +100,14 @@ select {
-ms-overflow-style
:
none
;
/* IE and Edge */
-ms-overflow-style
:
none
;
/* IE and Edge */
scrollbar-width
:
none
;
/* Firefox */
scrollbar-width
:
none
;
/* Firefox */
}
}
input
::-webkit-outer-spin-button
,
input
::-webkit-inner-spin-button
{
/* display: none; <- Crashes Chrome on hover */
-webkit-appearance
:
none
;
margin
:
0
;
/* <-- Apparently some margin are still there even though it's hidden */
}
input
[
type
=
'number'
]
{
-moz-appearance
:
textfield
;
/* Firefox */
}
src/lib/components/admin/AddUserModal.svelte
View file @
e10d029b
...
@@ -73,13 +73,16 @@
...
@@ -73,13 +73,16 @@
console.log(idx, columns);
console.log(idx, columns);
if (idx > 0) {
if (idx > 0) {
if (columns.length === 4 && ['admin', 'user', 'pending'].includes(columns[3])) {
if (
columns.length === 4 &&
['admin', 'user', 'pending'].includes(columns[3].toLowerCase())
) {
const res = await addUser(
const res = await addUser(
localStorage.token,
localStorage.token,
columns[0],
columns[0],
columns[1],
columns[1],
columns[2],
columns[2],
columns[3]
columns[3]
.toLowerCase()
).catch((error) => {
).catch((error) => {
toast.error(`Row ${idx + 1}: ${error}`);
toast.error(`Row ${idx + 1}: ${error}`);
return null;
return null;
...
...
src/lib/components/admin/Settings/General.svelte
View file @
e10d029b
...
@@ -123,7 +123,7 @@
...
@@ -123,7 +123,7 @@
<div class="flex mt-2 space-x-2">
<div class="flex mt-2 space-x-2">
<input
<input
class="w-full rounded py-
1.5
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
0
0 outline-none
border border-gray-100 dark:border-gray-600
"
class="w-full rounded
-lg
py-
2
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
5
0 outline-none"
type="text"
type="text"
placeholder={`https://example.com/webhook`}
placeholder={`https://example.com/webhook`}
bind:value={webhookUrl}
bind:value={webhookUrl}
...
@@ -140,7 +140,7 @@
...
@@ -140,7 +140,7 @@
<div class="flex mt-2 space-x-2">
<div class="flex mt-2 space-x-2">
<input
<input
class="w-full rounded py-
1.5
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
0
0 outline-none
border border-gray-100 dark:border-gray-600
"
class="w-full rounded
-lg
py-
2
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
5
0 outline-none"
type="text"
type="text"
placeholder={`e.g.) "30m","1h", "10d". `}
placeholder={`e.g.) "30m","1h", "10d". `}
bind:value={JWTExpiresIn}
bind:value={JWTExpiresIn}
...
...
src/lib/components/chat/MessageInput.svelte
View file @
e10d029b
...
@@ -412,7 +412,7 @@
...
@@ -412,7 +412,7 @@
{#if dragged}
{#if dragged}
<div
<div
class="fixed {$showSidebar
class="fixed {$showSidebar
? 'left-0
lg
:left-[260px]
lg
:w-[calc(100%-260px)]'
? 'left-0
md
:left-[260px]
md
:w-[calc(100%-260px)]'
: 'left-0'} w-full h-full flex z-50 touch-none pointer-events-none"
: 'left-0'} w-full h-full flex z-50 touch-none pointer-events-none"
id="dropzone"
id="dropzone"
role="region"
role="region"
...
@@ -428,9 +428,9 @@
...
@@ -428,9 +428,9 @@
</div>
</div>
{/if}
{/if}
<div class="fixed bottom-0 {$showSidebar ? 'left-0
lg
:left-[260px]' : 'left-0'} right-0">
<div class="fixed bottom-0 {$showSidebar ? 'left-0
md
:left-[260px]' : 'left-0'} right-0">
<div class="w-full">
<div class="w-full">
<div class="px-2.5
lg
:px-16 -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
<div class="px-2.5
md
:px-16 -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
<div class="flex flex-col max-w-5xl w-full">
<div class="flex flex-col max-w-5xl w-full">
<div class="relative">
<div class="relative">
{#if autoScroll === false && messages.length > 0}
{#if autoScroll === false && messages.length > 0}
...
@@ -535,7 +535,7 @@
...
@@ -535,7 +535,7 @@
</div>
</div>
<div class="bg-white dark:bg-gray-900">
<div class="bg-white dark:bg-gray-900">
<div class="max-w-6xl px-2.5
lg
:px-16 mx-auto inset-x-0">
<div class="max-w-6xl px-2.5
md
:px-16 mx-auto inset-x-0">
<div class=" pb-2">
<div class=" pb-2">
<input
<input
bind:this={filesInputElement}
bind:this={filesInputElement}
...
...
src/lib/components/chat/Messages/ResponseMessage.svelte
View file @
e10d029b
...
@@ -491,7 +491,7 @@
...
@@ -491,7 +491,7 @@
{#if message.done || siblings.length > 1}
{#if message.done || siblings.length > 1}
<div
<div
class=" flex justify-start
space-x-1
overflow-x-auto buttons text-gray-
7
00 dark:text-gray-500"
class=" flex justify-start overflow-x-auto buttons text-gray-
6
00 dark:text-gray-500"
>
>
{#if siblings.length > 1}
{#if siblings.length > 1}
<div class="flex self-center">
<div class="flex self-center">
...
@@ -553,7 +553,7 @@
...
@@ -553,7 +553,7 @@
<button
<button
class="{isLastMessage
class="{isLastMessage
? 'visible'
? 'visible'
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
: 'invisible group-hover:visible'} p-1
.5 hover:bg-black/5 dark:hover:bg-white/5
rounded
-lg
dark:hover:text-white hover:text-black transition"
on:click={() => {
on:click={() => {
editMessageHandler();
editMessageHandler();
}}
}}
...
@@ -562,7 +562,7 @@
...
@@ -562,7 +562,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
@@ -580,7 +580,7 @@
...
@@ -580,7 +580,7 @@
<button
<button
class="{isLastMessage
class="{isLastMessage
? 'visible'
? 'visible'
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition copy-response-button"
: 'invisible group-hover:visible'} p-1
.5 hover:bg-black/5 dark:hover:bg-white/5
rounded
-lg
dark:hover:text-white hover:text-black transition copy-response-button"
on:click={() => {
on:click={() => {
copyToClipboard(message.content);
copyToClipboard(message.content);
}}
}}
...
@@ -589,7 +589,7 @@
...
@@ -589,7 +589,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
@@ -602,83 +602,12 @@
...
@@ -602,83 +602,12 @@
</button>
</button>
</Tooltip>
</Tooltip>
{#if !readOnly}
<Tooltip content={$i18n.t('Good Response')} placement="bottom">
<button
class="{isLastMessage
? 'visible'
: 'invisible group-hover:visible'} p-1 rounded {message?.annotation
?.rating === 1
? 'bg-gray-100 dark:bg-gray-800'
: ''} dark:hover:text-white hover:text-black transition"
on:click={() => {
rateMessage(message.id, 1);
showRateComment = true;
window.setTimeout(() => {
document
.getElementById(`message-feedback-${message.id}`)
?.scrollIntoView();
}, 0);
}}
>
<svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="w-4 h-4"
xmlns="http://www.w3.org/2000/svg"
><path
d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"
/></svg
>
</button>
</Tooltip>
<Tooltip content={$i18n.t('Bad Response')} placement="bottom">
<button
class="{isLastMessage
? 'visible'
: 'invisible group-hover:visible'} p-1 rounded {message?.annotation
?.rating === -1
? 'bg-gray-100 dark:bg-gray-800'
: ''} dark:hover:text-white hover:text-black transition"
on:click={() => {
rateMessage(message.id, -1);
showRateComment = true;
window.setTimeout(() => {
document
.getElementById(`message-feedback-${message.id}`)
?.scrollIntoView();
}, 0);
}}
>
<svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="w-4 h-4"
xmlns="http://www.w3.org/2000/svg"
><path
d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"
/></svg
>
</button>
</Tooltip>
{/if}
<Tooltip content={$i18n.t('Read Aloud')} placement="bottom">
<Tooltip content={$i18n.t('Read Aloud')} placement="bottom">
<button
<button
id="speak-button-{message.id}"
id="speak-button-{message.id}"
class="{isLastMessage
class="{isLastMessage
? 'visible'
? 'visible'
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
: 'invisible group-hover:visible'} p-1
.5 hover:bg-black/5 dark:hover:bg-white/5
rounded
-lg
dark:hover:text-white hover:text-black transition"
on:click={() => {
on:click={() => {
if (!loadingSpeech) {
if (!loadingSpeech) {
toggleSpeakMessage(message);
toggleSpeakMessage(message);
...
@@ -725,7 +654,7 @@
...
@@ -725,7 +654,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
@@ -740,7 +669,7 @@
...
@@ -740,7 +669,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
@@ -759,7 +688,7 @@
...
@@ -759,7 +688,7 @@
<button
<button
class="{isLastMessage
class="{isLastMessage
? 'visible'
? 'visible'
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
: 'invisible group-hover:visible'}
p-1
.5 hover:bg-black/5 dark:hover:bg-white/5
rounded
-lg
dark:hover:text-white hover:text-black transition"
on:click={() => {
on:click={() => {
if (!generatingImage) {
if (!generatingImage) {
generateImage(message);
generateImage(message);
...
@@ -806,7 +735,7 @@
...
@@ -806,7 +735,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
@@ -826,7 +755,7 @@
...
@@ -826,7 +755,7 @@
<button
<button
class=" {isLastMessage
class=" {isLastMessage
? 'visible'
? 'visible'
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition whitespace-pre-wrap"
: 'invisible group-hover:visible'} p-1
.5 hover:bg-black/5 dark:hover:bg-white/5
rounded
-lg
dark:hover:text-white hover:text-black transition whitespace-pre-wrap"
on:click={() => {
on:click={() => {
console.log(message);
console.log(message);
}}
}}
...
@@ -836,7 +765,7 @@
...
@@ -836,7 +765,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
@@ -850,13 +779,84 @@
...
@@ -850,13 +779,84 @@
</Tooltip>
</Tooltip>
{/if}
{/if}
{#if !readOnly}
<Tooltip content={$i18n.t('Good Response')} placement="bottom">
<button
class="{isLastMessage
? 'visible'
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg {message
?.annotation?.rating === 1
? 'bg-gray-100 dark:bg-gray-800'
: ''} dark:hover:text-white hover:text-black transition"
on:click={() => {
rateMessage(message.id, 1);
showRateComment = true;
window.setTimeout(() => {
document
.getElementById(`message-feedback-${message.id}`)
?.scrollIntoView();
}, 0);
}}
>
<svg
stroke="currentColor"
fill="none"
stroke-width="2.3"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="w-4 h-4"
xmlns="http://www.w3.org/2000/svg"
><path
d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"
/></svg
>
</button>
</Tooltip>
<Tooltip content={$i18n.t('Bad Response')} placement="bottom">
<button
class="{isLastMessage
? 'visible'
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg {message
?.annotation?.rating === -1
? 'bg-gray-100 dark:bg-gray-800'
: ''} dark:hover:text-white hover:text-black transition"
on:click={() => {
rateMessage(message.id, -1);
showRateComment = true;
window.setTimeout(() => {
document
.getElementById(`message-feedback-${message.id}`)
?.scrollIntoView();
}, 0);
}}
>
<svg
stroke="currentColor"
fill="none"
stroke-width="2.3"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="w-4 h-4"
xmlns="http://www.w3.org/2000/svg"
><path
d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"
/></svg
>
</button>
</Tooltip>
{/if}
{#if isLastMessage && !readOnly}
{#if isLastMessage && !readOnly}
<Tooltip content={$i18n.t('Continue Response')} placement="bottom">
<Tooltip content={$i18n.t('Continue Response')} placement="bottom">
<button
<button
type="button"
type="button"
class="{isLastMessage
class="{isLastMessage
? 'visible'
? 'visible'
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition regenerate-response-button"
: 'invisible group-hover:visible'} p-1
.5 hover:bg-black/5 dark:hover:bg-white/5
rounded
-lg
dark:hover:text-white hover:text-black transition regenerate-response-button"
on:click={() => {
on:click={() => {
continueGeneration();
continueGeneration();
}}
}}
...
@@ -865,7 +865,7 @@
...
@@ -865,7 +865,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
@@ -888,14 +888,14 @@
...
@@ -888,14 +888,14 @@
type="button"
type="button"
class="{isLastMessage
class="{isLastMessage
? 'visible'
? 'visible'
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition regenerate-response-button"
: 'invisible group-hover:visible'} p-1
.5 hover:bg-black/5 dark:hover:bg-white/5
rounded
-lg
dark:hover:text-white hover:text-black transition regenerate-response-button"
on:click={regenerateResponse}
on:click={regenerateResponse}
>
>
<svg
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
...
src/lib/components/chat/Messages/UserMessage.svelte
View file @
e10d029b
...
@@ -55,14 +55,49 @@
...
@@ -55,14 +55,49 @@
</script>
</script>
<div class=" flex w-full user-message">
<div class=" flex w-full user-message">
{#if !($settings?.chatBubble ?? true)}
<ProfileImage
src={message.user
? $modelfiles.find((modelfile) => modelfile.tagName === message.user)?.imageUrl ??
'/user.png'
: user?.profile_image_url ?? '/user.png'}
/>
{/if}
<div class="w-full overflow-hidden">
<div class="w-full overflow-hidden">
{#if !($settings?.chatBubble ?? true)}
<div>
<Name>
{#if message.user}
{#if $modelfiles.map((modelfile) => modelfile.tagName).includes(message.user)}
{$modelfiles.find((modelfile) => modelfile.tagName === message.user)?.title}
{:else}
{$i18n.t('You')}
<span class=" text-gray-500 text-sm font-medium">{message?.user ?? ''}</span>
{/if}
{:else if $settings.showUsername}
{user.name}
{:else}
{$i18n.t('You')}
{/if}
{#if message.timestamp}
<span
class=" invisible group-hover:visible text-gray-400 text-xs font-medium uppercase"
>
{dayjs(message.timestamp * 1000).format($i18n.t('h:mm a'))}
</span>
{/if}
</Name>
</div>
{/if}
<div
<div
class="prose chat-{message.role} w-full max-w-full flex flex-col justify-end dark:prose-invert prose-headings:my-0 prose-p:my-0 prose-p:-mb-4 prose-pre:my-0 prose-table:my-0 prose-blockquote:my-0 prose-img:my-0 prose-ul:-my-4 prose-ol:-my-4 prose-li:-my-3 prose-ul:-mb-6 prose-ol:-mb-6 prose-li:-mb-4 whitespace-pre-line"
class="prose chat-{message.role} w-full max-w-full flex flex-col justify-end dark:prose-invert prose-headings:my-0 prose-p:my-0 prose-p:-mb-4 prose-pre:my-0 prose-table:my-0 prose-blockquote:my-0 prose-img:my-0 prose-ul:-my-4 prose-ol:-my-4 prose-li:-my-3 prose-ul:-mb-6 prose-ol:-mb-6 prose-li:-mb-4 whitespace-pre-line"
>
>
{#if message.files}
{#if message.files}
<div class="mt-2.5 mb-1 w-full flex flex-col justify-end overflow-x-auto gap-1
.5
flex-wrap">
<div class="mt-2.5 mb-1 w-full flex flex-col justify-end overflow-x-auto gap-1 flex-wrap">
{#each message.files as file}
{#each message.files as file}
<div class=
"
self-end
"
>
<div class=
{$settings?.chatBubble ?? true ? '
self-end
' : ''}
>
{#if file.type === 'image'}
{#if file.type === 'image'}
<img src={file.url} alt="input" class=" max-h-96 rounded-lg" draggable="false" />
<img src={file.url} alt="input" class=" max-h-96 rounded-lg" draggable="false" />
{:else if file.type === 'doc'}
{:else if file.type === 'doc'}
...
@@ -185,21 +220,80 @@
...
@@ -185,21 +220,80 @@
</div>
</div>
{:else}
{:else}
<div class="w-full">
<div class="w-full">
<div class="flex justify-end mb-2">
<div class="flex
{$settings?.chatBubble ?? true ? '
justify-end
' : ''}
mb-2">
<div
<div
class="rounded-3xl px-5 py-2 max-w-[90%] bg-gray-50 dark:bg-gray-850 {message.files
class="rounded-3xl {$settings?.chatBubble ?? true
? 'rounded-tr-lg'
? `max-w-[90%] px-5 py-2 bg-gray-50 dark:bg-gray-850 ${
: ''}"
message.files ? 'rounded-tr-lg' : ''
}`
: ''} "
>
>
<pre id="user-message">{message.content}</pre>
<pre id="user-message">{message.content}</pre>
</div>
</div>
</div>
</div>
<div class=" flex justify-end space-x-1 text-gray-700 dark:text-gray-500">
<div
class=" flex {$settings?.chatBubble ?? true
? 'justify-end'
: ''} text-gray-600 dark:text-gray-500"
>
{#if !($settings?.chatBubble ?? true)}
{#if siblings.length > 1}
<div class="flex self-center">
<button
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
on:click={() => {
showPreviousMessage(message);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2.5"
class="size-3.5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 19.5 8.25 12l7.5-7.5"
/>
</svg>
</button>
<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
{siblings.indexOf(message.id) + 1}/{siblings.length}
</div>
<button
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
on:click={() => {
showNextMessage(message);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2.5"
class="size-3.5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m8.25 4.5 7.5 7.5-7.5 7.5"
/>
</svg>
</button>
</div>
{/if}
{/if}
{#if !readOnly}
{#if !readOnly}
<Tooltip content={$i18n.t('Edit')} placement="bottom">
<Tooltip content={$i18n.t('Edit')} placement="bottom">
<button
<button
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition edit-user-message-button"
class="invisible group-hover:visible p-1
.5 hover:bg-black/5 dark:hover:bg-white/5
rounded
-lg
dark:hover:text-white hover:text-black transition edit-user-message-button"
on:click={() => {
on:click={() => {
editMessageHandler();
editMessageHandler();
}}
}}
...
@@ -208,7 +302,7 @@
...
@@ -208,7 +302,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
@@ -224,7 +318,7 @@
...
@@ -224,7 +318,7 @@
<Tooltip content={$i18n.t('Copy')} placement="bottom">
<Tooltip content={$i18n.t('Copy')} placement="bottom">
<button
<button
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
class="invisible group-hover:visible p-1
.5 hover:bg-black/5 dark:hover:bg-white/5
rounded
-lg
dark:hover:text-white hover:text-black transition"
on:click={() => {
on:click={() => {
copyToClipboard(message.content);
copyToClipboard(message.content);
}}
}}
...
@@ -233,7 +327,7 @@
...
@@ -233,7 +327,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
fill="none"
fill="none"
viewBox="0 0 24 24"
viewBox="0 0 24 24"
stroke-width="2"
stroke-width="2
.3
"
stroke="currentColor"
stroke="currentColor"
class="w-4 h-4"
class="w-4 h-4"
>
>
...
@@ -271,56 +365,59 @@
...
@@ -271,56 +365,59 @@
</button>
</button>
</Tooltip>
</Tooltip>
{/if}
{/if}
{#if siblings.length > 1}
<div class="flex self-center">
{#if $settings?.chatBubble ?? true}
<button
{#if siblings.length > 1}
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
<div class="flex self-center">
on:click={() => {
<button
showPreviousMessage(message);
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
}}
on:click={() => {
>
showPreviousMessage(message);
<svg
}}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2.5"
class="size-3.5"
>
>
<path
<svg
stroke-linecap="round"
xmlns="http://www.w3.org/2000/svg"
stroke-linejoin="round"
fill="none"
d="M15.75 19.5 8.25 12l7.5-7.5"
viewBox="0 0 24 24"
/>
stroke="currentColor"
</svg>
stroke-width="2.5"
</button>
class="size-3.5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 19.5 8.25 12l7.5-7.5"
/>
</svg>
</button>
<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
{siblings.indexOf(message.id) + 1}/{siblings.length}
{siblings.indexOf(message.id) + 1}/{siblings.length}
</div>
</div>
<button
<button
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
on:click={() => {
on:click={() => {
showNextMessage(message);
showNextMessage(message);
}}
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2.5"
class="size-3.5"
>
>
<path
<svg
stroke-linecap="round"
xmlns="http://www.w3.org/2000/svg"
stroke-linejoin="round"
fill="none"
d="m8.25 4.5 7.5 7.5-7.5 7.5"
viewBox="0 0 24 24"
/>
stroke="currentColor"
</svg>
stroke-width="2.5"
</button>
class="size-3.5"
</div>
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m8.25 4.5 7.5 7.5-7.5 7.5"
/>
</svg>
</button>
</div>
{/if}
{/if}
{/if}
</div>
</div>
</div>
</div>
...
...
src/lib/components/chat/Settings/Account.svelte
View file @
e10d029b
...
@@ -71,7 +71,7 @@
...
@@ -71,7 +71,7 @@
</script>
</script>
<div class="flex flex-col h-full justify-between text-sm">
<div class="flex flex-col h-full justify-between text-sm">
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[2
2
rem]">
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[2
5
rem]">
<input
<input
id="profile-image-input"
id="profile-image-input"
bind:this={profileImageInputElement}
bind:this={profileImageInputElement}
...
...
src/lib/components/chat/Settings/Advanced.svelte
View file @
e10d029b
...
@@ -84,7 +84,7 @@
...
@@ -84,7 +84,7 @@
{#if keepAlive !== null}
{#if keepAlive !== null}
<div class="flex mt-1 space-x-2">
<div class="flex mt-1 space-x-2">
<input
<input
class="w-full rounded py-
1.5
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
0
0 outline-none
border border-gray-100 dark:border-gray-600
"
class="w-full rounded
-lg
py-
2
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
5
0 outline-none"
type="text"
type="text"
placeholder={$i18n.t("e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.")}
placeholder={$i18n.t("e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.")}
bind:value={keepAlive}
bind:value={keepAlive}
...
...
src/lib/components/chat/Settings/Advanced/AdvancedParams.svelte
View file @
e10d029b
...
@@ -27,7 +27,7 @@
...
@@ -27,7 +27,7 @@
<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Seed')}</div>
<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Seed')}</div>
<div class=" flex-1 self-center">
<div class=" flex-1 self-center">
<input
<input
class="w-full rounded py-
1.5
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
0
0 outline-none
border border-gray-100 dark:border-gray-600
"
class="w-full rounded
-lg
py-
2
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
5
0 outline-none"
type="number"
type="number"
placeholder="Enter Seed"
placeholder="Enter Seed"
bind:value={options.seed}
bind:value={options.seed}
...
@@ -43,7 +43,7 @@
...
@@ -43,7 +43,7 @@
<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Stop Sequence')}</div>
<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Stop Sequence')}</div>
<div class=" flex-1 self-center">
<div class=" flex-1 self-center">
<input
<input
class="w-full rounded py-
1.5
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
0
0 outline-none
border border-gray-100 dark:border-gray-600
"
class="w-full rounded
-lg
py-
2
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
5
0 outline-none"
type="text"
type="text"
placeholder={$i18n.t('Enter stop sequence')}
placeholder={$i18n.t('Enter stop sequence')}
bind:value={options.stop}
bind:value={options.stop}
...
...
src/lib/components/chat/Settings/Audio.svelte
View file @
e10d029b
...
@@ -147,7 +147,7 @@
...
@@ -147,7 +147,7 @@
dispatch
(
'save'
);
dispatch
(
'save'
);
}}
}}
>
>
<
div
class
=
" space-y-3 pr-1.5 overflow-y-scroll max-h-[2
2
rem]"
>
<
div
class
=
" space-y-3 pr-1.5 overflow-y-scroll max-h-[2
5
rem]"
>
<
div
>
<
div
>
<
div
class
=
" mb-1 text-sm font-medium"
>{$
i18n
.
t
(
'STT Settings'
)}</
div
>
<
div
class
=
" mb-1 text-sm font-medium"
>{$
i18n
.
t
(
'STT Settings'
)}</
div
>
...
@@ -345,7 +345,7 @@
...
@@ -345,7 +345,7 @@
{/
if
}
{/
if
}
</
div
>
</
div
>
<
div
class
=
"flex justify-end
pt-3
text-sm font-medium"
>
<
div
class
=
"flex justify-end text-sm font-medium"
>
<
button
<
button
class
=
" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
class
=
" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
type
=
"submit"
type
=
"submit"
...
...
src/lib/components/chat/Settings/Connections.svelte
View file @
e10d029b
...
@@ -65,7 +65,7 @@
...
@@ -65,7 +65,7 @@
dispatch('save');
dispatch('save');
}}
}}
>
>
<div class=" pr-1.5 overflow-y-scroll max-h-[2
2
rem] space-y-3">
<div class=" pr-1.5 overflow-y-scroll max-h-[2
5
rem] space-y-3">
<div class=" space-y-3">
<div class=" space-y-3">
<div class="mt-2 space-y-2 pr-1.5">
<div class="mt-2 space-y-2 pr-1.5">
<div class="flex justify-between items-center text-sm">
<div class="flex justify-between items-center text-sm">
...
...
src/lib/components/chat/Settings/General.svelte
View file @
e10d029b
...
@@ -130,7 +130,7 @@
...
@@ -130,7 +130,7 @@
</script>
</script>
<div class="flex flex-col h-full justify-between text-sm">
<div class="flex flex-col h-full justify-between text-sm">
<div class=" pr-1.5 overflow-y-scroll max-h-[2
2
rem]">
<div class=" pr-1.5 overflow-y-scroll max-h-[2
5
rem]">
<div class="">
<div class="">
<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Settings')}</div>
<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Settings')}</div>
...
@@ -253,7 +253,7 @@
...
@@ -253,7 +253,7 @@
{#if keepAlive !== null}
{#if keepAlive !== null}
<div class="flex mt-1 space-x-2">
<div class="flex mt-1 space-x-2">
<input
<input
class="w-full rounded py-
1.5
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
0
0 outline-none
border border-gray-100 dark:border-gray-600
"
class="w-full rounded
-lg
py-
2
px-4 text-sm dark:text-gray-300 dark:bg-gray-8
5
0 outline-none"
type="text"
type="text"
placeholder={$i18n.t("e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.")}
placeholder={$i18n.t("e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.")}
bind:value={keepAlive}
bind:value={keepAlive}
...
...
src/lib/components/chat/Settings/Interface.svelte
View file @
e10d029b
...
@@ -22,6 +22,7 @@
...
@@ -22,6 +22,7 @@
// Interface
// Interface
let promptSuggestions = [];
let promptSuggestions = [];
let showUsername = false;
let showUsername = false;
let chatBubble = true;
const toggleSplitLargeChunks = async () => {
const toggleSplitLargeChunks = async () => {
splitLargeChunks = !splitLargeChunks;
splitLargeChunks = !splitLargeChunks;
...
@@ -33,6 +34,11 @@
...
@@ -33,6 +34,11 @@
saveSettings({ fullScreenMode: fullScreenMode });
saveSettings({ fullScreenMode: fullScreenMode });
};
};
const toggleChatBubble = async () => {
chatBubble = !chatBubble;
saveSettings({ chatBubble: chatBubble });
};
const toggleShowUsername = async () => {
const toggleShowUsername = async () => {
showUsername = !showUsername;
showUsername = !showUsername;
saveSettings({ showUsername: showUsername });
saveSettings({ showUsername: showUsername });
...
@@ -105,6 +111,7 @@
...
@@ -105,6 +111,7 @@
responseAutoCopy = settings.responseAutoCopy ?? false;
responseAutoCopy = settings.responseAutoCopy ?? false;
showUsername = settings.showUsername ?? false;
showUsername = settings.showUsername ?? false;
chatBubble = settings.chatBubble ?? true;
fullScreenMode = settings.fullScreenMode ?? false;
fullScreenMode = settings.fullScreenMode ?? false;
splitLargeChunks = settings.splitLargeChunks ?? false;
splitLargeChunks = settings.splitLargeChunks ?? false;
});
});
...
@@ -117,10 +124,30 @@
...
@@ -117,10 +124,30 @@
dispatch('save');
dispatch('save');
}}
}}
>
>
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[2
2
rem]">
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[2
5
rem]">
<div>
<div>
<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Add-ons')}</div>
<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Add-ons')}</div>
<div>
<div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Chat Bubble UI')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
on:click={() => {
toggleChatBubble();
}}
type="button"
>
{#if chatBubble === true}
<span class="ml-2 self-center">{$i18n.t('On')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Off')}</span>
{/if}
</button>
</div>
</div>
<div>
<div>
<div class=" py-0.5 flex w-full justify-between">
<div class=" py-0.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Title Auto-Generation')}</div>
<div class=" self-center text-xs font-medium">{$i18n.t('Title Auto-Generation')}</div>
...
@@ -283,7 +310,7 @@
...
@@ -283,7 +310,7 @@
{#if $user.role === 'admin'}
{#if $user.role === 'admin'}
<hr class=" dark:border-gray-700" />
<hr class=" dark:border-gray-700" />
<div class=" space-y-3 pr-1.5
overflow-y-scroll max-h-80
">
<div class=" space-y-3 pr-1.5">
<div class="flex w-full justify-between mb-2">
<div class="flex w-full justify-between mb-2">
<div class=" self-center text-sm font-semibold">
<div class=" self-center text-sm font-semibold">
{$i18n.t('Default Prompt Suggestions')}
{$i18n.t('Default Prompt Suggestions')}
...
...
src/lib/components/chat/SettingsModal.svelte
View file @
e10d029b
...
@@ -165,6 +165,32 @@
...
@@ -165,6 +165,32 @@
<div class=" self-center">{$i18n.t('Interface')}</div>
<div class=" self-center">{$i18n.t('Interface')}</div>
</button>
</button>
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'interface'
? 'bg-gray-200 dark:bg-gray-700'
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
on:click={() => {
selectedTab = 'interface';
}}
>
<div class=" self-center mr-2">
<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="M2 4.25A2.25 2.25 0 0 1 4.25 2h7.5A2.25 2.25 0 0 1 14 4.25v5.5A2.25 2.25 0 0 1 11.75 12h-1.312c.1.128.21.248.328.36a.75.75 0 0 1 .234.545v.345a.75.75 0 0 1-.75.75h-4.5a.75.75 0 0 1-.75-.75v-.345a.75.75 0 0 1 .234-.545c.118-.111.228-.232.328-.36H4.25A2.25 2.25 0 0 1 2 9.75v-5.5Zm2.25-.75a.75.75 0 0 0-.75.75v4.5c0 .414.336.75.75.75h7.5a.75.75 0 0 0 .75-.75v-4.5a.75.75 0 0 0-.75-.75h-7.5Z"
clip-rule="evenodd"
/>
</svg>
</div>
<div class=" self-center">{$i18n.t('Interface')}</div>
</button>
<button
<button
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
'audio'
'audio'
...
@@ -298,7 +324,7 @@
...
@@ -298,7 +324,7 @@
<div class=" self-center">{$i18n.t('About')}</div>
<div class=" self-center">{$i18n.t('About')}</div>
</button>
</button>
</div>
</div>
<div class="flex-1 md:min-h-[2
5
rem]">
<div class="flex-1 md:min-h-[2
8
rem]">
{#if selectedTab === 'general'}
{#if selectedTab === 'general'}
<General
<General
{getModels}
{getModels}
...
...
src/lib/components/chat/ShareChatModal.svelte
View file @
e10d029b
...
@@ -57,10 +57,23 @@
...
@@ -57,10 +57,23 @@
export let show = false;
export let show = false;
const isDifferentChat = (_chat) => {
if (!chat) {
return true;
}
if (!_chat) {
return false;
}
return chat.id !== _chat.id || chat.share_id !== _chat.share_id;
}
$: if (show) {
$: if (show) {
(async () => {
(async () => {
if (chatId) {
if (chatId) {
chat = await getChatById(localStorage.token, chatId);
const _chat = await getChatById(localStorage.token, chatId);
if (isDifferentChat(_chat)) {
chat = _chat;
}
} else {
} else {
chat = null;
chat = null;
console.log(chat);
console.log(chat);
...
@@ -137,6 +150,7 @@
...
@@ -137,6 +150,7 @@
<button
<button
class=" self-center flex items-center gap-1 px-3.5 py-2 rounded-xl text-sm font-medium bg-emerald-600 hover:bg-emerald-500 text-white"
class=" self-center flex items-center gap-1 px-3.5 py-2 rounded-xl text-sm font-medium bg-emerald-600 hover:bg-emerald-500 text-white"
type="button"
type="button"
id="copy-and-share-chat-button"
on:click={async () => {
on:click={async () => {
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
...
...
src/lib/components/common/Modal.svelte
View file @
e10d029b
...
@@ -16,9 +16,9 @@
...
@@ -16,9 +16,9 @@
} else if (size === 'sm') {
} else if (size === 'sm') {
return 'w-[30rem]';
return 'w-[30rem]';
} else if (size === 'md') {
} else if (size === 'md') {
return 'w-[44rem]';
} else {
return 'w-[48rem]';
return 'w-[48rem]';
} else {
return 'w-[50rem]';
}
}
};
};
...
...
Prev
1
2
3
4
Next
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