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
30aff2db
Commit
30aff2db
authored
Jan 04, 2024
by
Timothy J. Baek
Browse files
feat: enable backend ollama url update
parent
bdb3f507
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
555 additions
and
410 deletions
+555
-410
Dockerfile
Dockerfile
+0
-6
backend/apps/ollama/main.py
backend/apps/ollama/main.py
+66
-86
backend/apps/ollama/old_main.py
backend/apps/ollama/old_main.py
+176
-0
backend/main.py
backend/main.py
+3
-1
src/lib/apis/ollama/index.ts
src/lib/apis/ollama/index.ts
+103
-36
src/lib/components/chat/SettingsModal.svelte
src/lib/components/chat/SettingsModal.svelte
+146
-175
src/lib/constants.ts
src/lib/constants.ts
+2
-7
src/routes/(app)/+layout.svelte
src/routes/(app)/+layout.svelte
+3
-9
src/routes/(app)/+page.svelte
src/routes/(app)/+page.svelte
+26
-32
src/routes/(app)/c/[id]/+page.svelte
src/routes/(app)/c/[id]/+page.svelte
+27
-37
src/routes/(app)/modelfiles/+page.svelte
src/routes/(app)/modelfiles/+page.svelte
+1
-6
src/routes/(app)/modelfiles/create/+page.svelte
src/routes/(app)/modelfiles/create/+page.svelte
+1
-7
src/routes/(app)/modelfiles/edit/+page.svelte
src/routes/(app)/modelfiles/edit/+page.svelte
+1
-8
No files found.
Dockerfile
View file @
30aff2db
...
@@ -2,12 +2,6 @@
...
@@ -2,12 +2,6 @@
FROM
node:alpine as build
FROM
node:alpine as build
ARG
OLLAMA_API_BASE_URL='/ollama/api'
RUN
echo
$OLLAMA_API_BASE_URL
ENV
PUBLIC_API_BASE_URL $OLLAMA_API_BASE_URL
RUN
echo
$PUBLIC_API_BASE_URL
WORKDIR
/app
WORKDIR
/app
COPY
package.json package-lock.json ./
COPY
package.json package-lock.json ./
...
...
backend/apps/ollama/main.py
View file @
30aff2db
from
f
l
as
k
import
F
l
as
k
,
r
equest
,
Response
,
jsonify
from
fas
tapi
import
Fas
tAPI
,
R
equest
,
Response
,
HTTPException
,
Depends
from
f
lask_
cors
import
CORS
from
f
astapi.middleware.
cors
import
CORS
Middleware
from
fastapi.responses
import
StreamingResponse
import
requests
import
requests
import
json
import
json
from
pydantic
import
BaseModel
from
apps.web.models.users
import
Users
from
apps.web.models.users
import
Users
from
constants
import
ERROR_MESSAGES
from
constants
import
ERROR_MESSAGES
from
utils.utils
import
decode_token
from
utils.utils
import
decode_token
,
get_current_user
from
config
import
OLLAMA_API_BASE_URL
,
WEBUI_AUTH
from
config
import
OLLAMA_API_BASE_URL
,
WEBUI_AUTH
app
=
Flask
(
__name__
)
app
=
FastAPI
()
CORS
(
app
.
add_middleware
(
app
CORSMiddleware
,
)
# Enable Cross-Origin Resource Sharing (CORS) to allow requests from different domains
allow_origins
=
[
"*"
],
allow_credentials
=
True
,
allow_methods
=
[
"*"
],
allow_headers
=
[
"*"
],
)
# Define the target server URL
app
.
state
.
OLLAMA_API_BASE_URL
=
OLLAMA_API_BASE_URL
TARGET_SERVER_URL
=
OLLAMA_API_BASE_URL
# TARGET_SERVER_URL = OLLAMA_API_BASE_URL
@
app
.
route
(
"/"
,
defaults
=
{
"path"
:
""
},
methods
=
[
"GET"
,
"POST"
,
"PUT"
,
"DELETE"
])
@
app
.
route
(
"/<path:path>"
,
methods
=
[
"GET"
,
"POST"
,
"PUT"
,
"DELETE"
])
def
proxy
(
path
):
# Combine the base URL of the target server with the requested path
target_url
=
f
"
{
TARGET_SERVER_URL
}
/
{
path
}
"
print
(
target_url
)
# Get data from the original request
@
app
.
get
(
"/url"
)
data
=
request
.
get_data
()
async
def
get_ollama_api_url
(
user
=
Depends
(
get_current_user
)):
headers
=
dict
(
request
.
headers
)
if
user
and
user
.
role
==
"admin"
:
return
{
"OLLAMA_API_BASE_URL"
:
app
.
state
.
OLLAMA_API_BASE_URL
}
else
:
raise
HTTPException
(
status_code
=
401
,
detail
=
ERROR_MESSAGES
.
ACCESS_PROHIBITED
)
# Basic RBAC support
class
UrlUpdateForm
(
BaseModel
):
if
WEBUI_AUTH
:
url
:
str
if
"Authorization"
in
headers
:
_
,
credentials
=
headers
[
"Authorization"
].
split
()
token_data
=
decode_token
(
credentials
)
@
app
.
post
(
"/url/update"
)
if
token_data
is
None
or
"email"
not
in
token_data
:
async
def
update_ollama_api_url
(
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
form_data
:
UrlUpdateForm
,
user
=
Depends
(
get_current_user
)
):
user
=
Users
.
get_user_by_email
(
token_data
[
"email"
])
if
user
and
user
.
role
==
"admin"
:
if
user
:
app
.
state
.
OLLAMA_API_BASE_URL
=
form_data
.
url
# Only user and admin roles can access
return
{
"OLLAMA_API_BASE_URL"
:
app
.
state
.
OLLAMA_API_BASE_URL
}
if
user
.
role
in
[
"user"
,
"admin"
]:
if
path
in
[
"pull"
,
"delete"
,
"push"
,
"copy"
,
"create"
]:
# Only admin role can perform actions above
if
user
.
role
==
"admin"
:
pass
else
:
return
(
jsonify
({
"detail"
:
ERROR_MESSAGES
.
ACCESS_PROHIBITED
}),
401
,
)
else
:
pass
else
:
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
ACCESS_PROHIBITED
}),
401
else
:
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
else
:
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
else
:
else
:
pass
raise
HTTPException
(
status_code
=
401
,
detail
=
ERROR_MESSAGES
.
ACCESS_PROHIBITED
)
r
=
None
@
app
.
api_route
(
"/{path:path}"
,
methods
=
[
"GET"
,
"POST"
,
"PUT"
,
"DELETE"
])
async
def
proxy
(
path
:
str
,
request
:
Request
,
user
=
Depends
(
get_current_user
)):
target_url
=
f
"
{
app
.
state
.
OLLAMA_API_BASE_URL
}
/
{
path
}
"
body
=
await
request
.
body
()
headers
=
dict
(
request
.
headers
)
if
user
.
role
in
[
"user"
,
"admin"
]:
if
path
in
[
"pull"
,
"delete"
,
"push"
,
"copy"
,
"create"
]:
if
user
.
role
!=
"admin"
:
raise
HTTPException
(
status_code
=
401
,
detail
=
ERROR_MESSAGES
.
ACCESS_PROHIBITED
)
else
:
raise
HTTPException
(
status_code
=
401
,
detail
=
ERROR_MESSAGES
.
ACCESS_PROHIBITED
)
headers
.
pop
(
"Host"
,
None
)
headers
.
pop
(
"Host"
,
None
)
headers
.
pop
(
"Authorization"
,
None
)
headers
.
pop
(
"Authorization"
,
None
)
...
@@ -71,49 +70,30 @@ def proxy(path):
...
@@ -71,49 +70,30 @@ def proxy(path):
headers
.
pop
(
"Referer"
,
None
)
headers
.
pop
(
"Referer"
,
None
)
try
:
try
:
# Make a request to the target server
r
=
requests
.
request
(
r
=
requests
.
request
(
method
=
request
.
method
,
method
=
request
.
method
,
url
=
target_url
,
url
=
target_url
,
data
=
data
,
data
=
body
,
headers
=
headers
,
headers
=
headers
,
stream
=
True
,
# Enable streaming for server-sent events
stream
=
True
,
)
)
r
.
raise_for_status
()
r
.
raise_for_status
()
# Proxy the target server's response to the client
return
StreamingResponse
(
def
generate
():
r
.
iter_content
(
chunk_size
=
8192
),
for
chunk
in
r
.
iter_content
(
chunk_size
=
8192
):
status_code
=
r
.
status_code
,
yield
chunk
headers
=
dict
(
r
.
headers
),
)
response
=
Response
(
generate
(),
status
=
r
.
status_code
)
# Copy headers from the target server's response to the client's response
for
key
,
value
in
r
.
headers
.
items
():
response
.
headers
[
key
]
=
value
return
response
except
Exception
as
e
:
except
Exception
as
e
:
print
(
e
)
print
(
e
)
error_detail
=
"Ollama WebUI: Server Connection Error"
error_detail
=
"Ollama WebUI: Server Connection Error"
if
r
!=
None
:
if
r
is
not
None
:
print
(
r
.
text
)
try
:
res
=
r
.
json
()
res
=
r
.
json
()
if
"error"
in
res
:
if
"error"
in
res
:
error_detail
=
f
"Ollama:
{
res
[
'error'
]
}
"
error_detail
=
f
"Ollama:
{
res
[
'error'
]
}
"
print
(
res
)
except
:
error_detail
=
f
"Ollama:
{
e
}
"
return
(
jsonify
(
raise
HTTPException
(
status_code
=
r
.
status_code
,
detail
=
error_detail
)
{
"detail"
:
error_detail
,
"message"
:
str
(
e
),
}
),
400
,
)
if
__name__
==
"__main__"
:
app
.
run
(
debug
=
True
)
backend/apps/ollama/old_main.py
0 → 100644
View file @
30aff2db
from
flask
import
Flask
,
request
,
Response
,
jsonify
from
flask_cors
import
CORS
import
requests
import
json
from
apps.web.models.users
import
Users
from
constants
import
ERROR_MESSAGES
from
utils.utils
import
decode_token
from
config
import
OLLAMA_API_BASE_URL
,
WEBUI_AUTH
app
=
Flask
(
__name__
)
CORS
(
app
)
# Enable Cross-Origin Resource Sharing (CORS) to allow requests from different domains
# Define the target server URL
TARGET_SERVER_URL
=
OLLAMA_API_BASE_URL
@
app
.
route
(
"/url"
,
methods
=
[
"GET"
])
def
get_ollama_api_url
():
headers
=
dict
(
request
.
headers
)
if
"Authorization"
in
headers
:
_
,
credentials
=
headers
[
"Authorization"
].
split
()
token_data
=
decode_token
(
credentials
)
if
token_data
is
None
or
"email"
not
in
token_data
:
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
user
=
Users
.
get_user_by_email
(
token_data
[
"email"
])
if
user
and
user
.
role
==
"admin"
:
return
(
jsonify
({
"OLLAMA_API_BASE_URL"
:
TARGET_SERVER_URL
}),
200
,
)
else
:
return
(
jsonify
({
"detail"
:
ERROR_MESSAGES
.
ACCESS_PROHIBITED
}),
401
,
)
else
:
return
(
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
,
)
@
app
.
route
(
"/url/update"
,
methods
=
[
"POST"
])
def
update_ollama_api_url
():
headers
=
dict
(
request
.
headers
)
data
=
request
.
get_json
(
force
=
True
)
if
"Authorization"
in
headers
:
_
,
credentials
=
headers
[
"Authorization"
].
split
()
token_data
=
decode_token
(
credentials
)
if
token_data
is
None
or
"email"
not
in
token_data
:
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
user
=
Users
.
get_user_by_email
(
token_data
[
"email"
])
if
user
and
user
.
role
==
"admin"
:
TARGET_SERVER_URL
=
data
[
"url"
]
return
(
jsonify
({
"OLLAMA_API_BASE_URL"
:
TARGET_SERVER_URL
}),
200
,
)
else
:
return
(
jsonify
({
"detail"
:
ERROR_MESSAGES
.
ACCESS_PROHIBITED
}),
401
,
)
else
:
return
(
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
,
)
@
app
.
route
(
"/"
,
defaults
=
{
"path"
:
""
},
methods
=
[
"GET"
,
"POST"
,
"PUT"
,
"DELETE"
])
@
app
.
route
(
"/<path:path>"
,
methods
=
[
"GET"
,
"POST"
,
"PUT"
,
"DELETE"
])
def
proxy
(
path
):
# Combine the base URL of the target server with the requested path
target_url
=
f
"
{
TARGET_SERVER_URL
}
/
{
path
}
"
print
(
target_url
)
# Get data from the original request
data
=
request
.
get_data
()
headers
=
dict
(
request
.
headers
)
# Basic RBAC support
if
WEBUI_AUTH
:
if
"Authorization"
in
headers
:
_
,
credentials
=
headers
[
"Authorization"
].
split
()
token_data
=
decode_token
(
credentials
)
if
token_data
is
None
or
"email"
not
in
token_data
:
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
user
=
Users
.
get_user_by_email
(
token_data
[
"email"
])
if
user
:
# Only user and admin roles can access
if
user
.
role
in
[
"user"
,
"admin"
]:
if
path
in
[
"pull"
,
"delete"
,
"push"
,
"copy"
,
"create"
]:
# Only admin role can perform actions above
if
user
.
role
==
"admin"
:
pass
else
:
return
(
jsonify
({
"detail"
:
ERROR_MESSAGES
.
ACCESS_PROHIBITED
}),
401
,
)
else
:
pass
else
:
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
ACCESS_PROHIBITED
}),
401
else
:
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
else
:
return
jsonify
({
"detail"
:
ERROR_MESSAGES
.
UNAUTHORIZED
}),
401
else
:
pass
r
=
None
headers
.
pop
(
"Host"
,
None
)
headers
.
pop
(
"Authorization"
,
None
)
headers
.
pop
(
"Origin"
,
None
)
headers
.
pop
(
"Referer"
,
None
)
try
:
# Make a request to the target server
r
=
requests
.
request
(
method
=
request
.
method
,
url
=
target_url
,
data
=
data
,
headers
=
headers
,
stream
=
True
,
# Enable streaming for server-sent events
)
r
.
raise_for_status
()
# Proxy the target server's response to the client
def
generate
():
for
chunk
in
r
.
iter_content
(
chunk_size
=
8192
):
yield
chunk
response
=
Response
(
generate
(),
status
=
r
.
status_code
)
# Copy headers from the target server's response to the client's response
for
key
,
value
in
r
.
headers
.
items
():
response
.
headers
[
key
]
=
value
return
response
except
Exception
as
e
:
print
(
e
)
error_detail
=
"Ollama WebUI: Server Connection Error"
if
r
!=
None
:
print
(
r
.
text
)
res
=
r
.
json
()
if
"error"
in
res
:
error_detail
=
f
"Ollama:
{
res
[
'error'
]
}
"
print
(
res
)
return
(
jsonify
(
{
"detail"
:
error_detail
,
"message"
:
str
(
e
),
}
),
400
,
)
if
__name__
==
"__main__"
:
app
.
run
(
debug
=
True
)
backend/main.py
View file @
30aff2db
...
@@ -46,5 +46,7 @@ async def check_url(request: Request, call_next):
...
@@ -46,5 +46,7 @@ async def check_url(request: Request, call_next):
app
.
mount
(
"/api/v1"
,
webui_app
)
app
.
mount
(
"/api/v1"
,
webui_app
)
app
.
mount
(
"/ollama/api"
,
WSGIMiddleware
(
ollama_app
))
# app.mount("/ollama/api", WSGIMiddleware(ollama_app))
app
.
mount
(
"/ollama/api"
,
ollama_app
)
app
.
mount
(
"/"
,
SPAStaticFiles
(
directory
=
"../build"
,
html
=
True
),
name
=
"spa-static-files"
)
app
.
mount
(
"/"
,
SPAStaticFiles
(
directory
=
"../build"
,
html
=
True
),
name
=
"spa-static-files"
)
src/lib/apis/ollama/index.ts
View file @
30aff2db
import
{
OLLAMA_API_BASE_URL
}
from
'
$lib/constants
'
;
import
{
OLLAMA_API_BASE_URL
}
from
'
$lib/constants
'
;
export
const
getOllamaVersion
=
async
(
export
const
getOllamaAPIUrl
=
async
(
token
:
string
=
''
)
=>
{
base_url
:
string
=
OLLAMA_API_BASE_URL
,
token
:
string
=
''
)
=>
{
let
error
=
null
;
let
error
=
null
;
const
res
=
await
fetch
(
`
${
base_url
}
/version`
,
{
const
res
=
await
fetch
(
`
${
OLLAMA_API_BASE_URL
}
/url`
,
{
method
:
'
GET
'
,
headers
:
{
Accept
:
'
application/json
'
,
'
Content-Type
'
:
'
application/json
'
,
...(
token
&&
{
authorization
:
`Bearer
${
token
}
`
})
}
})
.
then
(
async
(
res
)
=>
{
if
(
!
res
.
ok
)
throw
await
res
.
json
();
return
res
.
json
();
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
if
(
'
detail
'
in
err
)
{
error
=
err
.
detail
;
}
else
{
error
=
'
Server connection failed
'
;
}
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
.
OLLAMA_API_BASE_URL
;
};
export
const
updateOllamaAPIUrl
=
async
(
token
:
string
=
''
,
url
:
string
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
OLLAMA_API_BASE_URL
}
/url/update`
,
{
method
:
'
POST
'
,
headers
:
{
Accept
:
'
application/json
'
,
'
Content-Type
'
:
'
application/json
'
,
...(
token
&&
{
authorization
:
`Bearer
${
token
}
`
})
},
body
:
JSON
.
stringify
({
url
:
url
})
})
.
then
(
async
(
res
)
=>
{
if
(
!
res
.
ok
)
throw
await
res
.
json
();
return
res
.
json
();
})
.
catch
((
err
)
=>
{
console
.
log
(
err
);
if
(
'
detail
'
in
err
)
{
error
=
err
.
detail
;
}
else
{
error
=
'
Server connection failed
'
;
}
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
.
OLLAMA_API_BASE_URL
;
};
export
const
getOllamaVersion
=
async
(
token
:
string
=
''
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
OLLAMA_API_BASE_URL
}
/version`
,
{
method
:
'
GET
'
,
method
:
'
GET
'
,
headers
:
{
headers
:
{
Accept
:
'
application/json
'
,
Accept
:
'
application/json
'
,
...
@@ -35,13 +99,10 @@ export const getOllamaVersion = async (
...
@@ -35,13 +99,10 @@ export const getOllamaVersion = async (
return
res
?.
version
??
''
;
return
res
?.
version
??
''
;
};
};
export
const
getOllamaModels
=
async
(
export
const
getOllamaModels
=
async
(
token
:
string
=
''
)
=>
{
base_url
:
string
=
OLLAMA_API_BASE_URL
,
token
:
string
=
''
)
=>
{
let
error
=
null
;
let
error
=
null
;
const
res
=
await
fetch
(
`
${
base_url
}
/tags`
,
{
const
res
=
await
fetch
(
`
${
OLLAMA_API_BASE_URL
}
/tags`
,
{
method
:
'
GET
'
,
method
:
'
GET
'
,
headers
:
{
headers
:
{
Accept
:
'
application/json
'
,
Accept
:
'
application/json
'
,
...
@@ -72,15 +133,10 @@ export const getOllamaModels = async (
...
@@ -72,15 +133,10 @@ export const getOllamaModels = async (
});
});
};
};
export
const
generateTitle
=
async
(
export
const
generateTitle
=
async
(
token
:
string
=
''
,
model
:
string
,
prompt
:
string
)
=>
{
base_url
:
string
=
OLLAMA_API_BASE_URL
,
token
:
string
=
''
,
model
:
string
,
prompt
:
string
)
=>
{
let
error
=
null
;
let
error
=
null
;
const
res
=
await
fetch
(
`
${
base_url
}
/generate`
,
{
const
res
=
await
fetch
(
`
${
OLLAMA_API_BASE_URL
}
/generate`
,
{
method
:
'
POST
'
,
method
:
'
POST
'
,
headers
:
{
headers
:
{
'
Content-Type
'
:
'
text/event-stream
'
,
'
Content-Type
'
:
'
text/event-stream
'
,
...
@@ -111,14 +167,10 @@ export const generateTitle = async (
...
@@ -111,14 +167,10 @@ export const generateTitle = async (
return
res
?.
response
??
'
New Chat
'
;
return
res
?.
response
??
'
New Chat
'
;
};
};
export
const
generateChatCompletion
=
async
(
export
const
generateChatCompletion
=
async
(
token
:
string
=
''
,
body
:
object
)
=>
{
base_url
:
string
=
OLLAMA_API_BASE_URL
,
token
:
string
=
''
,
body
:
object
)
=>
{
let
error
=
null
;
let
error
=
null
;
const
res
=
await
fetch
(
`
${
base_url
}
/chat`
,
{
const
res
=
await
fetch
(
`
${
OLLAMA_API_BASE_URL
}
/chat`
,
{
method
:
'
POST
'
,
method
:
'
POST
'
,
headers
:
{
headers
:
{
'
Content-Type
'
:
'
text/event-stream
'
,
'
Content-Type
'
:
'
text/event-stream
'
,
...
@@ -137,15 +189,10 @@ export const generateChatCompletion = async (
...
@@ -137,15 +189,10 @@ export const generateChatCompletion = async (
return
res
;
return
res
;
};
};
export
const
createModel
=
async
(
export
const
createModel
=
async
(
token
:
string
,
tagName
:
string
,
content
:
string
)
=>
{
base_url
:
string
=
OLLAMA_API_BASE_URL
,
token
:
string
,
tagName
:
string
,
content
:
string
)
=>
{
let
error
=
null
;
let
error
=
null
;
const
res
=
await
fetch
(
`
${
base_url
}
/create`
,
{
const
res
=
await
fetch
(
`
${
OLLAMA_API_BASE_URL
}
/create`
,
{
method
:
'
POST
'
,
method
:
'
POST
'
,
headers
:
{
headers
:
{
'
Content-Type
'
:
'
text/event-stream
'
,
'
Content-Type
'
:
'
text/event-stream
'
,
...
@@ -167,14 +214,10 @@ export const createModel = async (
...
@@ -167,14 +214,10 @@ export const createModel = async (
return
res
;
return
res
;
};
};
export
const
deleteModel
=
async
(
export
const
deleteModel
=
async
(
token
:
string
,
tagName
:
string
)
=>
{
base_url
:
string
=
OLLAMA_API_BASE_URL
,
token
:
string
,
tagName
:
string
)
=>
{
let
error
=
null
;
let
error
=
null
;
const
res
=
await
fetch
(
`
${
base_url
}
/delete`
,
{
const
res
=
await
fetch
(
`
${
OLLAMA_API_BASE_URL
}
/delete`
,
{
method
:
'
DELETE
'
,
method
:
'
DELETE
'
,
headers
:
{
headers
:
{
'
Content-Type
'
:
'
text/event-stream
'
,
'
Content-Type
'
:
'
text/event-stream
'
,
...
@@ -204,3 +247,27 @@ export const deleteModel = async (
...
@@ -204,3 +247,27 @@ export const deleteModel = async (
return
res
;
return
res
;
};
};
export
const
pullModel
=
async
(
token
:
string
,
tagName
:
string
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
OLLAMA_API_BASE_URL
}
/pull`
,
{
method
:
'
POST
'
,
headers
:
{
'
Content-Type
'
:
'
text/event-stream
'
,
Authorization
:
`Bearer
${
token
}
`
},
body
:
JSON
.
stringify
({
name
:
tagName
})
}).
catch
((
err
)
=>
{
error
=
err
;
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
;
};
src/lib/components/chat/SettingsModal.svelte
View file @
30aff2db
...
@@ -7,19 +7,23 @@
...
@@ -7,19 +7,23 @@
import { config, models, settings, user, chats } from '$lib/stores';
import { config, models, settings, user, chats } from '$lib/stores';
import { splitStream, getGravatarURL } from '$lib/utils';
import { splitStream, getGravatarURL } from '$lib/utils';
import { getOllamaVersion, getOllamaModels } from '$lib/apis/ollama';
import { createNewChat, deleteAllChats, getAllChats, getChatList } from '$lib/apis/chats';
import {
import {
WEB_UI_VERSION,
getOllamaVersion,
OLLAMA_API_BASE_URL,
getOllamaModels,
WEBUI_API_BASE_URL,
getOllamaAPIUrl,
WEBUI_BASE_URL
updateOllamaAPIUrl,
} from '$lib/constants';
pullModel,
createModel,
deleteModel
} from '$lib/apis/ollama';
import { createNewChat, deleteAllChats, getAllChats, getChatList } from '$lib/apis/chats';
import { WEB_UI_VERSION, WEBUI_API_BASE_URL } from '$lib/constants';
import Advanced from './Settings/Advanced.svelte';
import Advanced from './Settings/Advanced.svelte';
import Modal from '../common/Modal.svelte';
import Modal from '../common/Modal.svelte';
import { updateUserPassword } from '$lib/apis/auths';
import { updateUserPassword } from '$lib/apis/auths';
import { goto } from '$app/navigation';
import { goto } from '$app/navigation';
import Page from '../../../routes/(app)/+page.svelte';
export let show = false;
export let show = false;
...
@@ -33,7 +37,7 @@
...
@@ -33,7 +37,7 @@
let selectedTab = 'general';
let selectedTab = 'general';
// General
// General
let API_BASE_URL =
OLLAMA_API_BASE_URL
;
let API_BASE_URL =
''
;
let themes = ['dark', 'light', 'rose-pine dark', 'rose-pine-dawn light'];
let themes = ['dark', 'light', 'rose-pine dark', 'rose-pine-dawn light'];
let theme = 'dark';
let theme = 'dark';
let notificationEnabled = false;
let notificationEnabled = false;
...
@@ -139,19 +143,13 @@
...
@@ -139,19 +143,13 @@
// About
// About
let ollamaVersion = '';
let ollamaVersion = '';
const checkOllamaConnection = async () => {
const updateOllamaAPIUrlHandler = async () => {
if (API_BASE_URL === '') {
API_BASE_URL = await updateOllamaAPIUrl(localStorage.token, API_BASE_URL);
API_BASE_URL = OLLAMA_API_BASE_URL;
const _models = await getModels('ollama');
}
const _models = await getModels(API_BASE_URL, 'ollama');
if (_models.length > 0) {
if (_models.length > 0) {
toast.success('Server connection verified');
toast.success('Server connection verified');
await models.set(_models);
await models.set(_models);
saveSettings({
API_BASE_URL: API_BASE_URL
});
}
}
};
};
...
@@ -229,67 +227,60 @@
...
@@ -229,67 +227,60 @@
const pullModelHandler = async () => {
const pullModelHandler = async () => {
modelTransferring = true;
modelTransferring = true;
const res = await fetch(`${API_BASE_URL}/pull`, {
method: 'POST',
headers: {
'Content-Type': 'text/event-stream',
...($settings.authHeader && { Authorization: $settings.authHeader }),
...($user && { Authorization: `Bearer ${localStorage.token}` })
},
body: JSON.stringify({
name: modelTag
})
});
const reader = res.body
const res = await pullModel(localStorage.token, modelTag);
.pipeThrough(new TextDecoderStream())
.pipeThrough(splitStream('\n'))
.getReader();
while (true) {
if (res) {
const { value, done } = await reader.read();
const reader = res.body
if (done) break;
.pipeThrough(new TextDecoderStream())
.pipeThrough(splitStream('\n'))
.getReader();
try {
while (true) {
let lines = value.split('\n');
const { value, done } = await reader.read();
if (done) break;
for (const line of lines) {
try {
if (line !== '') {
let lines = value.split('\n');
console.log(line);
let data = JSON.parse(line);
console.log(data);
if (data.error) {
for (const line of lines) {
throw data.error;
if (line !== '') {
}
console.log(line);
let data = JSON.parse(line);
console.log(data);
if (data.
detail
) {
if (data.
error
) {
throw data.
detail
;
throw data.
error
;
}
}
if (data.status) {
if (
!
data.d
igest
) {
if (data.d
etail
) {
t
oast.success(data.status)
;
t
hrow data.detail
;
}
if (data.status
=== 'success'
) {
if (data.status) {
const notification = new Notification(`Ollama`,
{
if (!data.digest)
{
body: `Model '${modelTag}' has been successfully downloaded.`,
toast.success(data.status);
icon: '/favicon.png'
});
if (data.status === 'success') {
}
const notification = new Notification(`Ollama`, {
} else {
body: `Model '${modelTag}' has been successfully downloaded.`,
digest = data.digest;
icon: '/favicon.png'
if (data.completed) {
});
pullProgress = Math.round((data.completed / data.total) * 1000) / 10;
}
} else {
} else {
pullProgress = 100;
digest = data.digest;
if (data.completed) {
pullProgress = Math.round((data.completed / data.total) * 1000) / 10;
} else {
pullProgress = 100;
}
}
}
}
}
}
}
}
}
} catch (error) {
console.log(error);
toast.error(error);
}
}
} catch (error) {
console.log(error);
toast.error(error);
}
}
}
}
...
@@ -410,21 +401,11 @@
...
@@ -410,21 +401,11 @@
}
}
if (uploaded) {
if (uploaded) {
const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/create`, {
const res = await createModel(
method: 'POST',
localStorage.token,
headers: {
`${name}:latest`,
'Content-Type': 'text/event-stream',
`FROM @${modelFileDigest}\n${modelFileContent}`
...($settings.authHeader && { Authorization: $settings.authHeader }),
);
...($user && { Authorization: `Bearer ${localStorage.token}` })
},
body: JSON.stringify({
name: `${name}:latest`,
modelfile: `FROM @${modelFileDigest}\n${modelFileContent}`
})
}).catch((err) => {
console.log(err);
return null;
});
if (res && res.ok) {
if (res && res.ok) {
const reader = res.body
const reader = res.body
...
@@ -490,52 +471,44 @@
...
@@ -490,52 +471,44 @@
};
};
const deleteModelHandler = async () => {
const deleteModelHandler = async () => {
const res = await fetch(`${API_BASE_URL}/delete`, {
const res = await deleteModel(localStorage.token, deleteModelTag);
method: 'DELETE',
headers: {
'Content-Type': 'text/event-stream',
...($settings.authHeader && { Authorization: $settings.authHeader }),
...($user && { Authorization: `Bearer ${localStorage.token}` })
},
body: JSON.stringify({
name: deleteModelTag
})
});
const reader = res.body
if (res) {
.pipeThrough(new TextDecoderStream())
const reader = res.body
.pipeThrough(splitStream('\n'))
.pipeThrough(new TextDecoderStream())
.getReader();
.pipeThrough(splitStream('\n'))
.getReader();
while (true) {
while (true) {
const { value, done } = await reader.read();
const { value, done } = await reader.read();
if (done) break;
if (done) break;
try {
try {
let lines = value.split('\n');
let lines = value.split('\n');
for (const line of lines) {
for (const line of lines) {
if (line !== '' && line !== 'null') {
if (line !== '' && line !== 'null') {
console.log(line);
console.log(line);
let data = JSON.parse(line);
let data = JSON.parse(line);
console.log(data);
console.log(data);
if (data.error) {
if (data.error) {
throw data.error;
throw data.error;
}
}
if (data.detail) {
if (data.detail) {
throw data.detail;
throw data.detail;
}
}
if (data.status) {
if (data.status) {
}
} else {
toast.success(`Deleted ${deleteModelTag}`);
}
}
} else {
toast.success(`Deleted ${deleteModelTag}`);
}
}
} catch (error) {
console.log(error);
toast.error(error);
}
}
} catch (error) {
console.log(error);
toast.error(error);
}
}
}
}
...
@@ -543,13 +516,10 @@
...
@@ -543,13 +516,10 @@
models.set(await getModels());
models.set(await getModels());
};
};
const getModels = async (
url = '',
type = 'all') => {
const getModels = async (type = 'all') => {
let models = [];
let models = [];
models.push(
models.push(
...(await getOllamaModels(
...(await getOllamaModels(localStorage.token).catch((error) => {
url ? url : $settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
localStorage.token
).catch((error) => {
toast.error(error);
toast.error(error);
return [];
return [];
}))
}))
...
@@ -557,10 +527,10 @@
...
@@ -557,10 +527,10 @@
// If OpenAI API Key exists
// If OpenAI API Key exists
if (type === 'all' && $settings.OPENAI_API_KEY) {
if (type === 'all' && $settings.OPENAI_API_KEY) {
const API_BASE_URL = $settings.OPENAI_API_BASE_URL ?? 'https://api.openai.com/v1';
const
OPENAI_
API_BASE_URL = $settings.OPENAI_API_BASE_URL ?? 'https://api.openai.com/v1';
// Validate OPENAI_API_KEY
// Validate OPENAI_API_KEY
const openaiModelRes = await fetch(`${API_BASE_URL}/models`, {
const openaiModelRes = await fetch(`${
OPENAI_
API_BASE_URL}/models`, {
method: 'GET',
method: 'GET',
headers: {
headers: {
'Content-Type': 'application/json',
'Content-Type': 'application/json',
...
@@ -588,7 +558,7 @@
...
@@ -588,7 +558,7 @@
...openAIModels
...openAIModels
.map((model) => ({ name: model.id, external: true }))
.map((model) => ({ name: model.id, external: true }))
.filter((model) =>
.filter((model) =>
API_BASE_URL.includes('openai') ? model.name.includes('gpt') : true
OPENAI_
API_BASE_URL.includes('openai') ? model.name.includes('gpt') : true
)
)
]
]
: [])
: [])
...
@@ -624,15 +594,18 @@
...
@@ -624,15 +594,18 @@
};
};
onMount(async () => {
onMount(async () => {
console.log('settings', $user.role === 'admin');
if ($user.role === 'admin') {
API_BASE_URL = await getOllamaAPIUrl(localStorage.token);
}
let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
console.log(settings);
console.log(settings);
theme = localStorage.theme ?? 'dark';
theme = localStorage.theme ?? 'dark';
notificationEnabled = settings.notificationEnabled ?? false;
notificationEnabled = settings.notificationEnabled ?? false;
API_BASE_URL = settings.API_BASE_URL ?? OLLAMA_API_BASE_URL;
system = settings.system ?? '';
system = settings.system ?? '';
requestFormat = settings.requestFormat ?? '';
requestFormat = settings.requestFormat ?? '';
options.seed = settings.seed ?? 0;
options.seed = settings.seed ?? 0;
...
@@ -659,10 +632,7 @@
...
@@ -659,10 +632,7 @@
authContent = settings.authHeader.split(' ')[1];
authContent = settings.authHeader.split(' ')[1];
}
}
ollamaVersion = await getOllamaVersion(
ollamaVersion = await getOllamaVersion(localStorage.token).catch((error) => {
API_BASE_URL ?? OLLAMA_API_BASE_URL,
localStorage.token
).catch((error) => {
return '';
return '';
});
});
});
});
...
@@ -1026,51 +996,53 @@
...
@@ -1026,51 +996,53 @@
</div>
</div>
</div>
</div>
<hr class=" dark:border-gray-700" />
{#if $user.role === 'admin'}
<div>
<hr class=" dark:border-gray-700" />
<div class=" mb-2.5 text-sm font-medium">Ollama API URL</div>
<div>
<div class="flex w-full">
<div class=" mb-2.5 text-sm font-medium">Ollama API URL</div>
<div class="flex-1 mr-2">
<div class="flex w-full">
<input
<div class="flex-1 mr-2">
class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none"
<input
placeholder="Enter URL (e.g. http://localhost:8080/ollama/api)"
class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none"
bind:value={API_BASE_URL}
placeholder="Enter URL (e.g. http://localhost:8080/ollama/api)"
/>
bind:value={API_BASE_URL}
</div>
<button
class="px-3 bg-gray-200 hover:bg-gray-300 dark:bg-gray-600 dark:hover:bg-gray-700 rounded transition"
on:click={() => {
checkOllamaConnection();
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-4 h-4"
>
<path
fill-rule="evenodd"
d="M15.312 11.424a5.5 5.5 0 01-9.201 2.466l-.312-.311h2.433a.75.75 0 000-1.5H3.989a.75.75 0 00-.75.75v4.242a.75.75 0 001.5 0v-2.43l.31.31a7 7 0 0011.712-3.138.75.75 0 00-1.449-.39zm1.23-3.723a.75.75 0 00.219-.53V2.929a.75.75 0 00-1.5 0V5.36l-.31-.31A7 7 0 003.239 8.188a.75.75 0 101.448.389A5.5 5.5 0 0113.89 6.11l.311.31h-2.432a.75.75 0 000 1.5h4.243a.75.75 0 00.53-.219z"
clip-rule="evenodd"
/>
/>
</svg>
</div>
</button>
<button
</div>
class="px-3 bg-gray-200 hover:bg-gray-300 dark:bg-gray-600 dark:hover:bg-gray-700 rounded transition"
on:click={() => {
updateOllamaAPIUrlHandler();
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-4 h-4"
>
<path
fill-rule="evenodd"
d="M15.312 11.424a5.5 5.5 0 01-9.201 2.466l-.312-.311h2.433a.75.75 0 000-1.5H3.989a.75.75 0 00-.75.75v4.242a.75.75 0 001.5 0v-2.43l.31.31a7 7 0 0011.712-3.138.75.75 0 00-1.449-.39zm1.23-3.723a.75.75 0 00.219-.53V2.929a.75.75 0 00-1.5 0V5.36l-.31-.31A7 7 0 003.239 8.188a.75.75 0 101.448.389A5.5 5.5 0 0113.89 6.11l.311.31h-2.432a.75.75 0 000 1.5h4.243a.75.75 0 00.53-.219z"
clip-rule="evenodd"
/>
</svg>
</button>
</div>
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
The field above should be set to <span
The field above should be set to <span
class=" text-gray-500 dark:text-gray-300 font-medium">'/ollama/api'</span
class=" text-gray-500 dark:text-gray-300 font-medium">'/ollama/api'</span
>;
>;
<a
<a
class=" text-gray-500 dark:text-gray-300 font-medium"
class=" text-gray-500 dark:text-gray-300 font-medium"
href="https://github.com/ollama-webui/ollama-webui#troubleshooting"
href="https://github.com/ollama-webui/ollama-webui#troubleshooting"
target="_blank"
target="_blank"
>
>
Click here for help.
Click here for help.
</a>
</a>
</div>
</div>
</div>
</div>
{/if}
<hr class=" dark:border-gray-700" />
<hr class=" dark:border-gray-700" />
...
@@ -1088,7 +1060,6 @@
...
@@ -1088,7 +1060,6 @@
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded"
on:click={() => {
on:click={() => {
saveSettings({
saveSettings({
API_BASE_URL: API_BASE_URL === '' ? OLLAMA_API_BASE_URL : API_BASE_URL,
system: system !== '' ? system : undefined
system: system !== '' ? system : undefined
});
});
show = false;
show = false;
...
...
src/lib/constants.ts
View file @
30aff2db
import
{
dev
,
browser
}
from
'
$app/environment
'
;
import
{
dev
}
from
'
$app/environment
'
;
import
{
PUBLIC_API_BASE_URL
}
from
'
$env/static/public
'
;
export
const
OLLAMA_API_BASE_URL
=
dev
export
const
OLLAMA_API_BASE_URL
=
dev
?
`http://
${
location
.
hostname
}
:8080/ollama/api`
?
`http://
${
location
.
hostname
}
:8080/ollama/api`
:
PUBLIC_API_BASE_URL
===
''
:
'
/ollama/api
'
;
?
browser
?
`http://
${
location
.
hostname
}
:11434/api`
:
`http://localhost:11434/api`
:
PUBLIC_API_BASE_URL
;
export
const
WEBUI_BASE_URL
=
dev
?
`http://
${
location
.
hostname
}
:8080`
:
``
;
export
const
WEBUI_BASE_URL
=
dev
?
`http://
${
location
.
hostname
}
:8080`
:
``
;
export
const
WEBUI_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/api/v1`
;
export
const
WEBUI_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/api/v1`
;
...
...
src/routes/(app)/+layout.svelte
View file @
30aff2db
...
@@ -14,7 +14,7 @@
...
@@ -14,7 +14,7 @@
import { getOpenAIModels } from '$lib/apis/openai';
import { getOpenAIModels } from '$lib/apis/openai';
import { user, showSettings, settings, models, modelfiles, prompts } from '$lib/stores';
import { user, showSettings, settings, models, modelfiles, prompts } from '$lib/stores';
import {
OLLAMA_API_BASE_URL,
REQUIRED_OLLAMA_VERSION, WEBUI_API_BASE_URL } from '$lib/constants';
import { REQUIRED_OLLAMA_VERSION, WEBUI_API_BASE_URL } from '$lib/constants';
import SettingsModal from '$lib/components/chat/SettingsModal.svelte';
import SettingsModal from '$lib/components/chat/SettingsModal.svelte';
import Sidebar from '$lib/components/layout/Sidebar.svelte';
import Sidebar from '$lib/components/layout/Sidebar.svelte';
...
@@ -32,10 +32,7 @@
...
@@ -32,10 +32,7 @@
const getModels = async () => {
const getModels = async () => {
let models = [];
let models = [];
models.push(
models.push(
...(await getOllamaModels(
...(await getOllamaModels(localStorage.token).catch((error) => {
$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
localStorage.token
).catch((error) => {
toast.error(error);
toast.error(error);
return [];
return [];
}))
}))
...
@@ -58,10 +55,7 @@
...
@@ -58,10 +55,7 @@
const setOllamaVersion = async (version: string = '') => {
const setOllamaVersion = async (version: string = '') => {
if (version === '') {
if (version === '') {
version = await getOllamaVersion(
version = await getOllamaVersion(localStorage.token).catch((error) => {
$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
localStorage.token
).catch((error) => {
return '';
return '';
});
});
}
}
...
...
src/routes/(app)/+page.svelte
View file @
30aff2db
...
@@ -7,7 +7,6 @@
...
@@ -7,7 +7,6 @@
import { page } from '$app/stores';
import { page } from '$app/stores';
import { models, modelfiles, user, settings, chats, chatId, config } from '$lib/stores';
import { models, modelfiles, user, settings, chats, chatId, config } from '$lib/stores';
import { OLLAMA_API_BASE_URL } from '$lib/constants';
import { generateChatCompletion, generateTitle } from '$lib/apis/ollama';
import { generateChatCompletion, generateTitle } from '$lib/apis/ollama';
import { copyToClipboard, splitStream } from '$lib/utils';
import { copyToClipboard, splitStream } from '$lib/utils';
...
@@ -163,36 +162,32 @@
...
@@ -163,36 +162,32 @@
// Scroll down
// Scroll down
window.scrollTo({ top: document.body.scrollHeight });
window.scrollTo({ top: document.body.scrollHeight });
const res = await generateChatCompletion(
const res = await generateChatCompletion(localStorage.token, {
$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
model: model,
localStorage.token,
messages: [
{
$settings.system
model: model,
? {
messages: [
role: 'system',
$settings.system
content: $settings.system
? {
}
role: 'system',
: undefined,
content: $settings.system
...messages
}
]
: undefined,
.filter((message) => message)
...messages
.map((message) => ({
]
role: message.role,
.filter((message) => message)
content: message.content,
.map((message) => ({
...(message.files && {
role: message.role,
images: message.files
content: message.content,
.filter((file) => file.type === 'image')
...(message.files && {
.map((file) => file.url.slice(file.url.indexOf(',') + 1))
images: message.files
})
.filter((file) => file.type === 'image')
})),
.map((file) => file.url.slice(file.url.indexOf(',') + 1))
options: {
})
...($settings.options ?? {})
})),
},
options: {
format: $settings.requestFormat ?? undefined
...($settings.options ?? {})
});
},
format: $settings.requestFormat ?? undefined
}
);
if (res && res.ok) {
if (res && res.ok) {
const reader = res.body
const reader = res.body
...
@@ -595,7 +590,6 @@
...
@@ -595,7 +590,6 @@
const generateChatTitle = async (_chatId, userPrompt) => {
const generateChatTitle = async (_chatId, userPrompt) => {
if ($settings.titleAutoGenerate ?? true) {
if ($settings.titleAutoGenerate ?? true) {
const title = await generateTitle(
const title = await generateTitle(
$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
localStorage.token,
localStorage.token,
$settings?.titleAutoGenerateModel ?? selectedModels[0],
$settings?.titleAutoGenerateModel ?? selectedModels[0],
userPrompt
userPrompt
...
...
src/routes/(app)/c/[id]/+page.svelte
View file @
30aff2db
...
@@ -7,7 +7,6 @@
...
@@ -7,7 +7,6 @@
import { page } from '$app/stores';
import { page } from '$app/stores';
import { models, modelfiles, user, settings, chats, chatId } from '$lib/stores';
import { models, modelfiles, user, settings, chats, chatId } from '$lib/stores';
import { OLLAMA_API_BASE_URL } from '$lib/constants';
import { generateChatCompletion, generateTitle } from '$lib/apis/ollama';
import { generateChatCompletion, generateTitle } from '$lib/apis/ollama';
import { copyToClipboard, splitStream } from '$lib/utils';
import { copyToClipboard, splitStream } from '$lib/utils';
...
@@ -180,36 +179,32 @@
...
@@ -180,36 +179,32 @@
// Scroll down
// Scroll down
window.scrollTo({ top: document.body.scrollHeight });
window.scrollTo({ top: document.body.scrollHeight });
const res = await generateChatCompletion(
const res = await generateChatCompletion(localStorage.token, {
$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
model: model,
localStorage.token,
messages: [
{
$settings.system
model: model,
? {
messages: [
role: 'system',
$settings.system
content: $settings.system
? {
}
role: 'system',
: undefined,
content: $settings.system
...messages
}
]
: undefined,
.filter((message) => message)
...messages
.map((message) => ({
]
role: message.role,
.filter((message) => message)
content: message.content,
.map((message) => ({
...(message.files && {
role: message.role,
images: message.files
content: message.content,
.filter((file) => file.type === 'image')
...(message.files && {
.map((file) => file.url.slice(file.url.indexOf(',') + 1))
images: message.files
})
.filter((file) => file.type === 'image')
})),
.map((file) => file.url.slice(file.url.indexOf(',') + 1))
options: {
})
...($settings.options ?? {})
})),
},
options: {
format: $settings.requestFormat ?? undefined
...($settings.options ?? {})
});
},
format: $settings.requestFormat ?? undefined
}
);
if (res && res.ok) {
if (res && res.ok) {
const reader = res.body
const reader = res.body
...
@@ -611,12 +606,7 @@
...
@@ -611,12 +606,7 @@
const generateChatTitle = async (_chatId, userPrompt) => {
const generateChatTitle = async (_chatId, userPrompt) => {
if ($settings.titleAutoGenerate ?? true) {
if ($settings.titleAutoGenerate ?? true) {
const title = await generateTitle(
const title = await generateTitle(localStorage.token, selectedModels[0], userPrompt);
$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
localStorage.token,
selectedModels[0],
userPrompt
);
if (title) {
if (title) {
await setChatTitle(_chatId, title);
await setChatTitle(_chatId, title);
...
...
src/routes/(app)/modelfiles/+page.svelte
View file @
30aff2db
...
@@ -6,7 +6,6 @@
...
@@ -6,7 +6,6 @@
import { onMount } from 'svelte';
import { onMount } from 'svelte';
import { modelfiles, settings, user } from '$lib/stores';
import { modelfiles, settings, user } from '$lib/stores';
import { OLLAMA_API_BASE_URL } from '$lib/constants';
import { createModel, deleteModel } from '$lib/apis/ollama';
import { createModel, deleteModel } from '$lib/apis/ollama';
import {
import {
createNewModelfile,
createNewModelfile,
...
@@ -20,11 +19,7 @@
...
@@ -20,11 +19,7 @@
const deleteModelHandler = async (tagName) => {
const deleteModelHandler = async (tagName) => {
let success = null;
let success = null;
success = await deleteModel(
success = await deleteModel(localStorage.token, tagName);
$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
localStorage.token,
tagName
);
if (success) {
if (success) {
toast.success(`Deleted ${tagName}`);
toast.success(`Deleted ${tagName}`);
...
...
src/routes/(app)/modelfiles/create/+page.svelte
View file @
30aff2db
...
@@ -2,7 +2,6 @@
...
@@ -2,7 +2,6 @@
import { v4 as uuidv4 } from 'uuid';
import { v4 as uuidv4 } from 'uuid';
import { toast } from 'svelte-french-toast';
import { toast } from 'svelte-french-toast';
import { goto } from '$app/navigation';
import { goto } from '$app/navigation';
import { OLLAMA_API_BASE_URL } from '$lib/constants';
import { settings, user, config, modelfiles, models } from '$lib/stores';
import { settings, user, config, modelfiles, models } from '$lib/stores';
import Advanced from '$lib/components/chat/Settings/Advanced.svelte';
import Advanced from '$lib/components/chat/Settings/Advanced.svelte';
...
@@ -132,12 +131,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
...
@@ -132,12 +131,7 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
Object.keys(categories).filter((category) => categories[category]).length > 0 &&
Object.keys(categories).filter((category) => categories[category]).length > 0 &&
!$models.includes(tagName)
!$models.includes(tagName)
) {
) {
const res = await createModel(
const res = await createModel(localStorage.token, tagName, content);
$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
localStorage.token,
tagName,
content
);
if (res) {
if (res) {
const reader = res.body
const reader = res.body
...
...
src/routes/(app)/modelfiles/edit/+page.svelte
View file @
30aff2db
...
@@ -7,8 +7,6 @@
...
@@ -7,8 +7,6 @@
import { page } from '$app/stores';
import { page } from '$app/stores';
import { settings, user, config, modelfiles } from '$lib/stores';
import { settings, user, config, modelfiles } from '$lib/stores';
import { OLLAMA_API_BASE_URL } from '$lib/constants';
import { splitStream } from '$lib/utils';
import { splitStream } from '$lib/utils';
import { createModel } from '$lib/apis/ollama';
import { createModel } from '$lib/apis/ollama';
...
@@ -104,12 +102,7 @@
...
@@ -104,12 +102,7 @@
content !== '' &&
content !== '' &&
Object.keys(categories).filter((category) => categories[category]).length > 0
Object.keys(categories).filter((category) => categories[category]).length > 0
) {
) {
const res = await createModel(
const res = await createModel(localStorage.token, tagName, content);
$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL,
localStorage.token,
tagName,
content
);
if (res) {
if (res) {
const reader = res.body
const reader = res.body
...
...
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