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
30d10480
Commit
30d10480
authored
Apr 30, 2024
by
Jannik Streidl
Browse files
resolved the conflicts
😍
parents
142f82ba
5e168e6f
Changes
50
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
264 additions
and
60 deletions
+264
-60
.github/workflows/format-build-frontend.yaml
.github/workflows/format-build-frontend.yaml
+3
-0
.github/workflows/integration-test.yml
.github/workflows/integration-test.yml
+131
-0
backend/apps/openai/main.py
backend/apps/openai/main.py
+5
-2
backend/apps/rag/main.py
backend/apps/rag/main.py
+44
-7
backend/apps/rag/utils.py
backend/apps/rag/utils.py
+16
-14
backend/config.py
backend/config.py
+7
-1
backend/constants.py
backend/constants.py
+4
-0
backend/dev.sh
backend/dev.sh
+0
-0
backend/main.py
backend/main.py
+10
-5
backend/requirements.txt
backend/requirements.txt
+3
-2
src/lib/apis/streaming/index.ts
src/lib/apis/streaming/index.ts
+5
-1
src/lib/components/admin/UserChatsModal.svelte
src/lib/components/admin/UserChatsModal.svelte
+6
-3
src/lib/components/chat/Messages/Placeholder.svelte
src/lib/components/chat/Messages/Placeholder.svelte
+2
-2
src/lib/components/chat/Messages/ResponseMessage.svelte
src/lib/components/chat/Messages/ResponseMessage.svelte
+12
-10
src/lib/components/chat/Messages/UserMessage.svelte
src/lib/components/chat/Messages/UserMessage.svelte
+4
-4
src/lib/components/chat/ModelSelector/Selector.svelte
src/lib/components/chat/ModelSelector/Selector.svelte
+1
-1
src/lib/components/chat/Settings/Advanced/AdvancedParams.svelte
...b/components/chat/Settings/Advanced/AdvancedParams.svelte
+4
-5
src/lib/components/chat/Settings/Interface.svelte
src/lib/components/chat/Settings/Interface.svelte
+1
-0
src/lib/components/common/Modal.svelte
src/lib/components/common/Modal.svelte
+2
-2
src/lib/components/common/Tags.svelte
src/lib/components/common/Tags.svelte
+4
-1
No files found.
.github/workflows/format-build-frontend.yaml
View file @
30d10480
...
...
@@ -29,6 +29,9 @@ jobs:
-
name
:
Format Frontend
run
:
npm run format
-
name
:
Run i18next
run
:
npm run i18n:parse
-
name
:
Check for Changes After Format
run
:
git diff --exit-code
...
...
.github/workflows/integration-test.yml
View file @
30d10480
...
...
@@ -53,3 +53,134 @@ jobs:
name
:
compose-logs
path
:
compose-logs.txt
if-no-files-found
:
ignore
migration_test
:
name
:
Run Migration Tests
runs-on
:
ubuntu-latest
services
:
postgres
:
image
:
postgres
env
:
POSTGRES_PASSWORD
:
postgres
options
:
>-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports
:
-
5432:5432
# mysql:
# image: mysql
# env:
# MYSQL_ROOT_PASSWORD: mysql
# MYSQL_DATABASE: mysql
# options: >-
# --health-cmd "mysqladmin ping -h localhost"
# --health-interval 10s
# --health-timeout 5s
# --health-retries 5
# ports:
# - 3306:3306
steps
:
-
name
:
Checkout Repository
uses
:
actions/checkout@v4
-
name
:
Set up Python
uses
:
actions/setup-python@v2
with
:
python-version
:
${{ matrix.python-version }}
-
name
:
Set up uv
uses
:
yezz123/setup-uv@v4
with
:
uv-venv
:
venv
-
name
:
Activate virtualenv
run
:
|
. venv/bin/activate
echo PATH=$PATH >> $GITHUB_ENV
-
name
:
Install dependencies
run
:
|
uv pip install -r backend/requirements.txt
-
name
:
Test backend with SQLite
id
:
sqlite
env
:
WEBUI_SECRET_KEY
:
secret-key
GLOBAL_LOG_LEVEL
:
debug
run
:
|
cd backend
uvicorn main:app --port "8080" --forwarded-allow-ips '*' &
UVICORN_PID=$!
# Wait up to 20 seconds for the server to start
for i in {1..20}; do
curl -s http://localhost:8080/api/config > /dev/null && break
sleep 1
if [ $i -eq 20 ]; then
echo "Server failed to start"
kill -9 $UVICORN_PID
exit 1
fi
done
# Check that the server is still running after 5 seconds
sleep 5
if ! kill -0 $UVICORN_PID; then
echo "Server has stopped"
exit 1
fi
-
name
:
Test backend with Postgres
if
:
success() || steps.sqlite.conclusion == 'failure'
env
:
WEBUI_SECRET_KEY
:
secret-key
GLOBAL_LOG_LEVEL
:
debug
DATABASE_URL
:
postgresql://postgres:postgres@localhost:5432/postgres
run
:
|
cd backend
uvicorn main:app --port "8081" --forwarded-allow-ips '*' &
UVICORN_PID=$!
# Wait up to 20 seconds for the server to start
for i in {1..20}; do
curl -s http://localhost:8081/api/config > /dev/null && break
sleep 1
if [ $i -eq 20 ]; then
echo "Server failed to start"
kill -9 $UVICORN_PID
exit 1
fi
done
# Check that the server is still running after 5 seconds
sleep 5
if ! kill -0 $UVICORN_PID; then
echo "Server has stopped"
exit 1
fi
# - name: Test backend with MySQL
# if: success() || steps.sqlite.conclusion == 'failure' || steps.postgres.conclusion == 'failure'
# env:
# WEBUI_SECRET_KEY: secret-key
# GLOBAL_LOG_LEVEL: debug
# DATABASE_URL: mysql://root:mysql@localhost:3306/mysql
# run: |
# cd backend
# uvicorn main:app --port "8083" --forwarded-allow-ips '*' &
# UVICORN_PID=$!
# # Wait up to 20 seconds for the server to start
# for i in {1..20}; do
# curl -s http://localhost:8083/api/config > /dev/null && break
# sleep 1
# if [ $i -eq 20 ]; then
# echo "Server failed to start"
# kill -9 $UVICORN_PID
# exit 1
# fi
# done
# # Check that the server is still running after 5 seconds
# sleep 5
# if ! kill -0 $UVICORN_PID; then
# echo "Server has stopped"
# exit 1
# fi
backend/apps/openai/main.py
View file @
30d10480
...
...
@@ -171,6 +171,7 @@ async def fetch_url(url, key):
def
merge_models_lists
(
model_lists
):
log
.
info
(
f
"merge_models_lists
{
model_lists
}
"
)
merged_list
=
[]
for
idx
,
models
in
enumerate
(
model_lists
):
...
...
@@ -199,14 +200,16 @@ async def get_all_models():
]
responses
=
await
asyncio
.
gather
(
*
tasks
)
log
.
info
(
f
"get_all_models:responses()
{
responses
}
"
)
models
=
{
"data"
:
merge_models_lists
(
list
(
map
(
lambda
response
:
(
response
[
"data"
]
if
response
and
"data"
in
response
else
None
if
(
response
and
"data"
in
response
)
else
(
response
if
isinstance
(
response
,
list
)
else
None
)
),
responses
,
)
...
...
backend/apps/rag/main.py
View file @
30d10480
...
...
@@ -31,6 +31,11 @@ from langchain_community.document_loaders import (
)
from
langchain.text_splitter
import
RecursiveCharacterTextSplitter
import
validators
import
urllib.parse
import
socket
from
pydantic
import
BaseModel
from
typing
import
Optional
import
mimetypes
...
...
@@ -84,6 +89,7 @@ from config import (
CHUNK_SIZE
,
CHUNK_OVERLAP
,
RAG_TEMPLATE
,
ENABLE_LOCAL_WEB_FETCH
,
)
from
constants
import
ERROR_MESSAGES
...
...
@@ -391,16 +397,16 @@ def query_doc_handler(
return
query_doc_with_hybrid_search
(
collection_name
=
form_data
.
collection_name
,
query
=
form_data
.
query
,
embeddings_function
=
app
.
state
.
EMBEDDING_FUNCTION
,
reranking_function
=
app
.
state
.
sentence_transformer_rf
,
embedding_function
=
app
.
state
.
EMBEDDING_FUNCTION
,
k
=
form_data
.
k
if
form_data
.
k
else
app
.
state
.
TOP_K
,
reranking_function
=
app
.
state
.
sentence_transformer_rf
,
r
=
form_data
.
r
if
form_data
.
r
else
app
.
state
.
RELEVANCE_THRESHOLD
,
)
else
:
return
query_doc
(
collection_name
=
form_data
.
collection_name
,
query
=
form_data
.
query
,
embedding
s
_function
=
app
.
state
.
EMBEDDING_FUNCTION
,
embedding_function
=
app
.
state
.
EMBEDDING_FUNCTION
,
k
=
form_data
.
k
if
form_data
.
k
else
app
.
state
.
TOP_K
,
)
except
Exception
as
e
:
...
...
@@ -429,16 +435,16 @@ def query_collection_handler(
return
query_collection_with_hybrid_search
(
collection_names
=
form_data
.
collection_names
,
query
=
form_data
.
query
,
embeddings_function
=
app
.
state
.
EMBEDDING_FUNCTION
,
reranking_function
=
app
.
state
.
sentence_transformer_rf
,
embedding_function
=
app
.
state
.
EMBEDDING_FUNCTION
,
k
=
form_data
.
k
if
form_data
.
k
else
app
.
state
.
TOP_K
,
reranking_function
=
app
.
state
.
sentence_transformer_rf
,
r
=
form_data
.
r
if
form_data
.
r
else
app
.
state
.
RELEVANCE_THRESHOLD
,
)
else
:
return
query_collection
(
collection_names
=
form_data
.
collection_names
,
query
=
form_data
.
query
,
embedding
s
_function
=
app
.
state
.
EMBEDDING_FUNCTION
,
embedding_function
=
app
.
state
.
EMBEDDING_FUNCTION
,
k
=
form_data
.
k
if
form_data
.
k
else
app
.
state
.
TOP_K
,
)
...
...
@@ -454,7 +460,7 @@ def query_collection_handler(
def
store_web
(
form_data
:
StoreWebForm
,
user
=
Depends
(
get_current_user
)):
# "https://www.gutenberg.org/files/1727/1727-h/1727-h.htm"
try
:
loader
=
WebBaseL
oader
(
form_data
.
url
)
loader
=
get_web_l
oader
(
form_data
.
url
)
data
=
loader
.
load
()
collection_name
=
form_data
.
collection_name
...
...
@@ -475,6 +481,37 @@ def store_web(form_data: StoreWebForm, user=Depends(get_current_user)):
)
def
get_web_loader
(
url
:
str
):
# Check if the URL is valid
if
isinstance
(
validators
.
url
(
url
),
validators
.
ValidationError
):
raise
ValueError
(
ERROR_MESSAGES
.
INVALID_URL
)
if
not
ENABLE_LOCAL_WEB_FETCH
:
# Local web fetch is disabled, filter out any URLs that resolve to private IP addresses
parsed_url
=
urllib
.
parse
.
urlparse
(
url
)
# Get IPv4 and IPv6 addresses
ipv4_addresses
,
ipv6_addresses
=
resolve_hostname
(
parsed_url
.
hostname
)
# Check if any of the resolved addresses are private
# This is technically still vulnerable to DNS rebinding attacks, as we don't control WebBaseLoader
for
ip
in
ipv4_addresses
:
if
validators
.
ipv4
(
ip
,
private
=
True
):
raise
ValueError
(
ERROR_MESSAGES
.
INVALID_URL
)
for
ip
in
ipv6_addresses
:
if
validators
.
ipv6
(
ip
,
private
=
True
):
raise
ValueError
(
ERROR_MESSAGES
.
INVALID_URL
)
return
WebBaseLoader
(
url
)
def
resolve_hostname
(
hostname
):
# Get address information
addr_info
=
socket
.
getaddrinfo
(
hostname
,
None
)
# Extract IP addresses from address information
ipv4_addresses
=
[
info
[
4
][
0
]
for
info
in
addr_info
if
info
[
0
]
==
socket
.
AF_INET
]
ipv6_addresses
=
[
info
[
4
][
0
]
for
info
in
addr_info
if
info
[
0
]
==
socket
.
AF_INET6
]
return
ipv4_addresses
,
ipv6_addresses
def
store_data_in_vector_db
(
data
,
collection_name
,
overwrite
:
bool
=
False
)
->
bool
:
text_splitter
=
RecursiveCharacterTextSplitter
(
...
...
backend/apps/rag/utils.py
View file @
30d10480
...
...
@@ -35,6 +35,7 @@ def query_doc(
try
:
collection
=
CHROMA_CLIENT
.
get_collection
(
name
=
collection_name
)
query_embeddings
=
embedding_function
(
query
)
result
=
collection
.
query
(
query_embeddings
=
[
query_embeddings
],
n_results
=
k
,
...
...
@@ -76,9 +77,9 @@ def query_doc_with_hybrid_search(
compressor
=
RerankCompressor
(
embedding_function
=
embedding_function
,
top_n
=
k
,
reranking_function
=
reranking_function
,
r_score
=
r
,
top_n
=
k
,
)
compression_retriever
=
ContextualCompressionRetriever
(
...
...
@@ -91,6 +92,7 @@ def query_doc_with_hybrid_search(
"documents"
:
[[
d
.
page_content
for
d
in
result
]],
"metadatas"
:
[[
d
.
metadata
for
d
in
result
]],
}
log
.
info
(
f
"query_doc_with_hybrid_search:result
{
result
}
"
)
return
result
except
Exception
as
e
:
...
...
@@ -167,7 +169,6 @@ def query_collection_with_hybrid_search(
reranking_function
,
r
:
float
,
):
results
=
[]
for
collection_name
in
collection_names
:
try
:
...
...
@@ -182,7 +183,6 @@ def query_collection_with_hybrid_search(
results
.
append
(
result
)
except
:
pass
return
merge_and_sort_query_results
(
results
,
k
=
k
,
reverse
=
True
)
...
...
@@ -443,13 +443,15 @@ class ChromaRetriever(BaseRetriever):
metadatas
=
results
[
"metadatas"
][
0
]
documents
=
results
[
"documents"
][
0
]
return
[
Document
(
metadata
=
metadatas
[
idx
],
page_content
=
documents
[
idx
],
results
=
[]
for
idx
in
range
(
len
(
ids
)):
results
.
append
(
Document
(
metadata
=
metadatas
[
idx
],
page_content
=
documents
[
idx
],
)
)
for
idx
in
range
(
len
(
ids
))
]
return
results
import
operator
...
...
@@ -465,9 +467,9 @@ from sentence_transformers import util
class
RerankCompressor
(
BaseDocumentCompressor
):
embedding_function
:
Any
top_n
:
int
reranking_function
:
Any
r_score
:
float
top_n
:
int
class
Config
:
extra
=
Extra
.
forbid
...
...
@@ -479,7 +481,9 @@ class RerankCompressor(BaseDocumentCompressor):
query
:
str
,
callbacks
:
Optional
[
Callbacks
]
=
None
,
)
->
Sequence
[
Document
]:
if
self
.
reranking_function
:
reranking
=
self
.
reranking_function
is
not
None
if
reranking
:
scores
=
self
.
reranking_function
.
predict
(
[(
query
,
doc
.
page_content
)
for
doc
in
documents
]
)
...
...
@@ -496,9 +500,7 @@ class RerankCompressor(BaseDocumentCompressor):
(
d
,
s
)
for
d
,
s
in
docs_with_scores
if
s
>=
self
.
r_score
]
reverse
=
self
.
reranking_function
is
not
None
result
=
sorted
(
docs_with_scores
,
key
=
operator
.
itemgetter
(
1
),
reverse
=
reverse
)
result
=
sorted
(
docs_with_scores
,
key
=
operator
.
itemgetter
(
1
),
reverse
=
True
)
final_results
=
[]
for
doc
,
doc_score
in
result
[:
self
.
top_n
]:
metadata
=
doc
.
metadata
...
...
backend/config.py
View file @
30d10480
...
...
@@ -168,7 +168,11 @@ except:
STATIC_DIR
=
str
(
Path
(
os
.
getenv
(
"STATIC_DIR"
,
"./static"
)).
resolve
())
shutil
.
copyfile
(
f
"
{
FRONTEND_BUILD_DIR
}
/favicon.png"
,
f
"
{
STATIC_DIR
}
/favicon.png"
)
frontend_favicon
=
f
"
{
FRONTEND_BUILD_DIR
}
/favicon.png"
if
os
.
path
.
exists
(
frontend_favicon
):
shutil
.
copyfile
(
frontend_favicon
,
f
"
{
STATIC_DIR
}
/favicon.png"
)
else
:
logging
.
warning
(
f
"Frontend favicon not found at
{
frontend_favicon
}
"
)
####################################
# CUSTOM_NAME
...
...
@@ -516,6 +520,8 @@ RAG_TEMPLATE = os.environ.get("RAG_TEMPLATE", DEFAULT_RAG_TEMPLATE)
RAG_OPENAI_API_BASE_URL
=
os
.
getenv
(
"RAG_OPENAI_API_BASE_URL"
,
OPENAI_API_BASE_URL
)
RAG_OPENAI_API_KEY
=
os
.
getenv
(
"RAG_OPENAI_API_KEY"
,
OPENAI_API_KEY
)
ENABLE_LOCAL_WEB_FETCH
=
os
.
getenv
(
"ENABLE_LOCAL_WEB_FETCH"
,
"False"
).
lower
()
==
"true"
####################################
# Transcribe
####################################
...
...
backend/constants.py
View file @
30d10480
...
...
@@ -71,3 +71,7 @@ class ERROR_MESSAGES(str, Enum):
EMPTY_CONTENT
=
"The content provided is empty. Please ensure that there is text or data present before proceeding."
DB_NOT_SQLITE
=
"This feature is only available when running with SQLite databases."
INVALID_URL
=
(
"Oops! The URL you provided is invalid. Please double-check and try again."
)
backend/dev.sh
100644 → 100755
View file @
30d10480
File mode changed from 100644 to 100755
backend/main.py
View file @
30d10480
...
...
@@ -318,11 +318,16 @@ async def get_manifest_json():
app
.
mount
(
"/static"
,
StaticFiles
(
directory
=
STATIC_DIR
),
name
=
"static"
)
app
.
mount
(
"/cache"
,
StaticFiles
(
directory
=
CACHE_DIR
),
name
=
"cache"
)
app
.
mount
(
"/"
,
SPAStaticFiles
(
directory
=
FRONTEND_BUILD_DIR
,
html
=
True
),
name
=
"spa-static-files"
,
)
if
os
.
path
.
exists
(
FRONTEND_BUILD_DIR
):
app
.
mount
(
"/"
,
SPAStaticFiles
(
directory
=
FRONTEND_BUILD_DIR
,
html
=
True
),
name
=
"spa-static-files"
,
)
else
:
log
.
warning
(
f
"Frontend build directory not found at '
{
FRONTEND_BUILD_DIR
}
'. Serving API only."
)
@
app
.
on_event
(
"shutdown"
)
...
...
backend/requirements.txt
View file @
30d10480
...
...
@@ -19,8 +19,8 @@ psycopg2-binary
pymysql
bcrypt
litellm==1.35.
17
litellm[proxy]==1.35.
17
litellm==1.35.
28
litellm[proxy]==1.35.
28
boto3
...
...
@@ -43,6 +43,7 @@ pandas
openpyxl
pyxlsb
xlrd
validators
opencv-python-headless
rapidocr-onnxruntime
...
...
src/lib/apis/streaming/index.ts
View file @
30d10480
...
...
@@ -73,7 +73,11 @@ async function* streamLargeDeltasAsRandomChunks(
const
chunkSize
=
Math
.
min
(
Math
.
floor
(
Math
.
random
()
*
3
)
+
1
,
content
.
length
);
const
chunk
=
content
.
slice
(
0
,
chunkSize
);
yield
{
done
:
false
,
value
:
chunk
};
await
sleep
(
5
);
// Do not sleep if the tab is hidden
// Timers are throttled to 1s in hidden tabs
if
(
document
?.
visibilityState
!==
'
hidden
'
)
{
await
sleep
(
5
);
}
content
=
content
.
slice
(
chunkSize
);
}
}
...
...
src/lib/components/admin/UserChatsModal.svelte
View file @
30d10480
...
...
@@ -70,7 +70,7 @@
>
<tr>
<th scope="col" class="px-3 py-2"> {$i18n.t('Name')} </th>
<th scope="col" class="px-3 py-2 hidden md:flex"> {$i18n.t('Created
A
t')} </th>
<th scope="col" class="px-3 py-2 hidden md:flex"> {$i18n.t('Created
a
t')} </th>
<th scope="col" class="px-3 py-2 text-right" />
</tr>
</thead>
...
...
@@ -96,7 +96,7 @@
<td class="px-3 py-1 text-right">
<div class="flex justify-end w-full">
<Tooltip content=
"
Delete Chat
"
>
<Tooltip content=
{$i18n.t('
Delete Chat
')}
>
<button
class="self-center w-fit text-sm px-2 py-2 hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
on:click={async () => {
...
...
@@ -133,7 +133,10 @@
{/each} -->
</div>
{:else}
<div class="text-left text-sm w-full mb-8">{user.name} has no conversations.</div>
<div class="text-left text-sm w-full mb-8">
{user.name}
{$i18n.t('has no conversations.')}
</div>
{/if}
</div>
</div>
...
...
src/lib/components/chat/Messages/Placeholder.svelte
View file @
30d10480
...
...
@@ -38,8 +38,8 @@
/>
{:else}
<img
src={
models
.l
e
ng
th
===
1
? `
${WEBUI_BASE_URL}/static/favicon
.png`
src={
$i18n
.l
a
ng
uage
===
'dg-DG'
? `
/doge
.png`
: `${WEBUI_BASE_URL}/static/favicon.png`}
class=" size-12 rounded-full border-[1px] border-gray-200 dark:border-none"
alt="logo"
...
...
src/lib/components/chat/Messages/ResponseMessage.svelte
View file @
30d10480
...
...
@@ -325,7 +325,9 @@
{#key message.id}
<div class=" flex w-full message-{message.id}" id="message-{message.id}">
<ProfileImage
src={modelfiles[message.model]?.imageUrl ?? `${WEBUI_BASE_URL}/static/favicon.png`}
src={modelfiles[message.model]?.imageUrl ?? $i18n.language === 'dg-DG'
? `/doge.png`
: `${WEBUI_BASE_URL}/static/favicon.png`}
/>
<div class="w-full overflow-hidden">
...
...
@@ -377,7 +379,7 @@
<div class=" mt-2 mb-1 flex justify-center space-x-2 text-sm font-medium">
<button
class="px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg
-lg
"
class="px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
on:click={() => {
editMessageConfirmHandler();
}}
...
...
@@ -492,7 +494,7 @@
{/if}
{#if !readOnly}
<Tooltip content=
"
Edit
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Edit
')}
placement="bottom">
<button
class="{isLastMessage
? 'visible'
...
...
@@ -519,7 +521,7 @@
</Tooltip>
{/if}
<Tooltip content=
"
Copy
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Copy
')}
placement="bottom">
<button
class="{isLastMessage
? 'visible'
...
...
@@ -546,7 +548,7 @@
</Tooltip>
{#if !readOnly}
<Tooltip content=
"
Good Response
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Good Response
')}
placement="bottom">
<button
class="{isLastMessage
? 'visible'
...
...
@@ -581,7 +583,7 @@
</button>
</Tooltip>
<Tooltip content=
"
Bad Response
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Bad Response
')}
placement="bottom">
<button
class="{isLastMessage
? 'visible'
...
...
@@ -616,7 +618,7 @@
</Tooltip>
{/if}
<Tooltip content=
"
Read Aloud
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Read Aloud
')}
placement="bottom">
<button
id="speak-button-{message.id}"
class="{isLastMessage
...
...
@@ -765,7 +767,7 @@
{/if}
{#if message.info}
<Tooltip content=
"
Generation Info
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Generation Info
')}
placement="bottom">
<button
class=" {isLastMessage
? 'visible'
...
...
@@ -794,7 +796,7 @@
{/if}
{#if isLastMessage && !readOnly}
<Tooltip content=
"
Continue Response
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Continue Response
')}
placement="bottom">
<button
type="button"
class="{isLastMessage
...
...
@@ -826,7 +828,7 @@
</button>
</Tooltip>
<Tooltip content=
"
Regenerate
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Regenerate
')}
placement="bottom">
<button
type="button"
class="{isLastMessage
...
...
src/lib/components/chat/Messages/UserMessage.svelte
View file @
30d10480
...
...
@@ -193,7 +193,7 @@
<div class=" mt-2 mb-1 flex justify-center space-x-2 text-sm font-medium">
<button
id="save-edit-message-button"
class="px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg
-lg
"
class="px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
on:click={() => {
editMessageConfirmHandler();
}}
...
...
@@ -266,7 +266,7 @@
{/if}
{#if !readOnly}
<Tooltip content=
"
Edit
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Edit
')}
placement="bottom">
<button
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition edit-user-message-button"
on:click={() => {
...
...
@@ -291,7 +291,7 @@
</Tooltip>
{/if}
<Tooltip content=
"
Copy
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Copy
')}
placement="bottom">
<button
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
on:click={() => {
...
...
@@ -316,7 +316,7 @@
</Tooltip>
{#if !isFirstMessage && !readOnly}
<Tooltip content=
"
Delete
"
placement="bottom">
<Tooltip content=
{$i18n.t('
Delete
')}
placement="bottom">
<button
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
on:click={() => {
...
...
src/lib/components/chat/ModelSelector/Selector.svelte
View file @
30d10480
...
...
@@ -21,7 +21,7 @@
export let value = '';
export let placeholder = 'Select a model';
export let searchEnabled = true;
export let searchPlaceholder = $i18n.t(
`
Search a model
`
);
export let searchPlaceholder = $i18n.t(
'
Search a model
'
);
export let items = [{ value: 'mango', label: 'Mango' }];
...
...
src/lib/components/chat/Settings/Advanced/AdvancedParams.svelte
View file @
30d10480
...
...
@@ -492,8 +492,8 @@
<input
id="steps-range"
type="range"
min="1"
max="1
6
000"
min="
-
1"
max="1
0240
000"
step="1"
bind:value={options.num_ctx}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
...
...
@@ -504,9 +504,8 @@
bind:value={options.num_ctx}
type="number"
class=" bg-transparent text-center w-14"
min="1"
max="16000"
step="1"
min="-1"
step="10"
/>
</div>
</div>
...
...
src/lib/components/chat/Settings/Interface.svelte
View file @
30d10480
...
...
@@ -106,6 +106,7 @@
responseAutoCopy = settings.responseAutoCopy ?? false;
showUsername = settings.showUsername ?? false;
fullScreenMode = settings.fullScreenMode ?? false;
splitLargeChunks = settings.splitLargeChunks ?? false;
});
</script>
...
...
src/lib/components/common/Modal.svelte
View file @
30d10480
...
...
@@ -51,7 +51,7 @@
bind:this={modalElement}
class=" fixed top-0 right-0 left-0 bottom-0 bg-black/60 w-full min-h-screen h-screen flex justify-center z-[9999] overflow-hidden overscroll-contain"
in:fade={{ duration: 10 }}
on:
click
={() => {
on:
mousedown
={() => {
show = false;
}}
>
...
...
@@ -60,7 +60,7 @@
size
)} mx-2 bg-gray-50 dark:bg-gray-900 shadow-3xl"
in:flyAndScale
on:
click
={(e) => {
on:
mousedown
={(e) => {
e.stopPropagation();
}}
>
...
...
src/lib/components/common/Tags.svelte
View file @
30d10480
<script lang="ts">
import TagInput from './Tags/TagInput.svelte';
import TagList from './Tags/TagList.svelte';
import { getContext } from 'svelte';
const i18n = getContext('i18n');
export let tags = [];
...
...
@@ -17,7 +20,7 @@
/>
<TagInput
label={tags.length == 0 ? 'Add Tags' : ''}
label={tags.length == 0 ?
$i18n.t(
'Add Tags'
)
: ''}
on:add={(e) => {
addTag(e.detail);
}}
...
...
Prev
1
2
3
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