forked from open-webui/open-webui
main #2
41 changed files with 1104 additions and 814 deletions
|
@ -7,7 +7,6 @@ node_modules
|
|||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
__pycache__
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Ollama URL for the backend to connect
|
||||
# The path '/ollama/api' will be redirected to the specified backend URL
|
||||
OLLAMA_API_BASE_URL='http://localhost:11434/api'
|
||||
# The path '/ollama' will be redirected to the specified backend URL
|
||||
OLLAMA_BASE_URL='http://localhost:11434'
|
||||
|
||||
OPENAI_API_BASE_URL=''
|
||||
OPENAI_API_KEY=''
|
||||
|
|
14
.github/workflows/build-release.yml
vendored
14
.github/workflows/build-release.yml
vendored
|
@ -19,24 +19,34 @@ jobs:
|
|||
echo "No changes to package.json"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
- name: Get version number from package.json
|
||||
id: get_version
|
||||
run: |
|
||||
VERSION=$(jq -r '.version' package.json)
|
||||
echo "::set-output name=version::$VERSION"
|
||||
|
||||
- name: Extract latest CHANGELOG entry
|
||||
id: changelog
|
||||
run: |
|
||||
CHANGELOG_CONTENT=$(awk '/^## \[/{n++} n==1' CHANGELOG.md)
|
||||
echo "CHANGELOG_CONTENT<<EOF"
|
||||
echo "$CHANGELOG_CONTENT"
|
||||
echo "EOF"
|
||||
echo "::set-output name=content::${CHANGELOG_CONTENT}"
|
||||
|
||||
- name: Create GitHub release
|
||||
uses: actions/github-script@v5
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const changelog = `${{ steps.changelog.outputs.content }}`;
|
||||
const release = await github.rest.repos.createRelease({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
tag_name: `v${{ steps.get_version.outputs.version }}`,
|
||||
name: `v${{ steps.get_version.outputs.version }}`,
|
||||
body: 'Automatically created new release',
|
||||
body: changelog,
|
||||
})
|
||||
console.log(`Created release ${release.data.html_url}`)
|
||||
|
||||
|
|
32
CHANGELOG.md
32
CHANGELOG.md
|
@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.1.110] - 2024-03-06
|
||||
|
||||
### Added
|
||||
|
||||
- **🌐 Multiple OpenAI Servers Support**: Enjoy seamless integration with multiple OpenAI-compatible APIs, now supported natively.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **🔍 OCR Issue**: Resolved PDF parsing issue caused by OCR malfunction.
|
||||
- **🚫 RAG Issue**: Fixed the RAG functionality, ensuring it operates smoothly.
|
||||
- **📄 "Add Docs" Model Button**: Addressed the non-functional behavior of the "Add Docs" model button.
|
||||
|
||||
## [0.1.109] - 2024-03-06
|
||||
|
||||
### Added
|
||||
|
||||
- **🔄 Multiple Ollama Servers Support**: Enjoy enhanced scalability and performance with support for multiple Ollama servers in a single WebUI. Load balancing features are now available, providing improved efficiency (#788, #278).
|
||||
- **🔧 Support for Claude 3 and Gemini**: Responding to user requests, we've expanded our toolset to include Claude 3 and Gemini, offering a wider range of functionalities within our platform (#1064).
|
||||
- **🔍 OCR Functionality for PDF Loader**: We've augmented our PDF loader with Optical Character Recognition (OCR) capabilities. Now, extract text from scanned documents and images within PDFs, broadening the scope of content processing (#1050).
|
||||
|
||||
### Fixed
|
||||
|
||||
- **🛠️ RAG Collection**: Implemented a dynamic mechanism to recreate RAG collections, ensuring users have up-to-date and accurate data (#1031).
|
||||
- **📝 User Agent Headers**: Fixed issue of RAG web requests being sent with empty user_agent headers, reducing rejections from certain websites. Realistic headers are now utilized for these requests (#1024).
|
||||
- **⏹️ Playground Cancel Functionality**: Introducing a new "Cancel" option for stopping Ollama generation in the Playground, enhancing user control and usability (#1006).
|
||||
- **🔤 Typographical Error in 'ASSISTANT' Field**: Corrected a typographical error in the 'ASSISTANT' field within the GGUF model upload template for accuracy and consistency (#1061).
|
||||
|
||||
### Changed
|
||||
|
||||
- **🔄 Refactored Message Deletion Logic**: Streamlined message deletion process for improved efficiency and user experience, simplifying interactions within the platform (#1004).
|
||||
- **⚠️ Deprecation of `OLLAMA_API_BASE_URL`**: Deprecated `OLLAMA_API_BASE_URL` environment variable; recommend using `OLLAMA_BASE_URL` instead. Refer to our documentation for further details.
|
||||
|
||||
## [0.1.108] - 2024-03-02
|
||||
|
||||
### Added
|
||||
|
|
|
@ -20,7 +20,7 @@ FROM python:3.11-slim-bookworm as base
|
|||
ENV ENV=prod
|
||||
ENV PORT ""
|
||||
|
||||
ENV OLLAMA_API_BASE_URL "/ollama/api"
|
||||
ENV OLLAMA_BASE_URL "/ollama"
|
||||
|
||||
ENV OPENAI_API_BASE_URL ""
|
||||
ENV OPENAI_API_KEY ""
|
||||
|
@ -53,6 +53,8 @@ WORKDIR /app/backend
|
|||
# install python dependencies
|
||||
COPY ./backend/requirements.txt ./requirements.txt
|
||||
|
||||
RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y
|
||||
|
||||
RUN pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu --no-cache-dir
|
||||
RUN pip3 install -r requirements.txt --no-cache-dir
|
||||
|
||||
|
|
|
@ -95,10 +95,10 @@ Don't forget to explore our sibling project, [Open WebUI Community](https://open
|
|||
|
||||
- **If Ollama is on a Different Server**, use this command:
|
||||
|
||||
- To connect to Ollama on another server, change the `OLLAMA_API_BASE_URL` to the server's URL:
|
||||
- To connect to Ollama on another server, change the `OLLAMA_BASE_URL` to the server's URL:
|
||||
|
||||
```bash
|
||||
docker run -d -p 3000:8080 -e OLLAMA_API_BASE_URL=https://example.com/api -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
|
||||
docker run -d -p 3000:8080 -e OLLAMA_BASE_URL=https://example.com -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
|
||||
```
|
||||
|
||||
- After installation, you can access Open WebUI at [http://localhost:3000](http://localhost:3000). Enjoy! 😄
|
||||
|
@ -110,7 +110,7 @@ If you're experiencing connection issues, it’s often due to the WebUI docker c
|
|||
**Example Docker Command**:
|
||||
|
||||
```bash
|
||||
docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_API_BASE_URL=http://127.0.0.1:11434/api --name open-webui --restart always ghcr.io/open-webui/open-webui:main
|
||||
docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_BASE_URL=http://127.0.0.1:11434 --name open-webui --restart always ghcr.io/open-webui/open-webui:main
|
||||
```
|
||||
|
||||
### Other Installation Methods
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
The Open WebUI system is designed to streamline interactions between the client (your browser) and the Ollama API. At the heart of this design is a backend reverse proxy, enhancing security and resolving CORS issues.
|
||||
|
||||
- **How it Works**: The Open WebUI is designed to interact with the Ollama API through a specific route. When a request is made from the WebUI to Ollama, it is not directly sent to the Ollama API. Initially, the request is sent to the Open WebUI backend via `/ollama/api` route. From there, the backend is responsible for forwarding the request to the Ollama API. This forwarding is accomplished by using the route specified in the `OLLAMA_API_BASE_URL` environment variable. Therefore, a request made to `/ollama/api` in the WebUI is effectively the same as making a request to `OLLAMA_API_BASE_URL` in the backend. For instance, a request to `/ollama/api/tags` in the WebUI is equivalent to `OLLAMA_API_BASE_URL/tags` in the backend.
|
||||
- **How it Works**: The Open WebUI is designed to interact with the Ollama API through a specific route. When a request is made from the WebUI to Ollama, it is not directly sent to the Ollama API. Initially, the request is sent to the Open WebUI backend via `/ollama` route. From there, the backend is responsible for forwarding the request to the Ollama API. This forwarding is accomplished by using the route specified in the `OLLAMA_BASE_URL` environment variable. Therefore, a request made to `/ollama` in the WebUI is effectively the same as making a request to `OLLAMA_BASE_URL` in the backend. For instance, a request to `/ollama/api/tags` in the WebUI is equivalent to `OLLAMA_BASE_URL/api/tags` in the backend.
|
||||
|
||||
- **Security Benefits**: This design prevents direct exposure of the Ollama API to the frontend, safeguarding against potential CORS (Cross-Origin Resource Sharing) issues and unauthorized access. Requiring authentication to access the Ollama API further enhances this security layer.
|
||||
|
||||
|
@ -15,7 +15,7 @@ If you're experiencing connection issues, it’s often due to the WebUI docker c
|
|||
**Example Docker Command**:
|
||||
|
||||
```bash
|
||||
docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_API_BASE_URL=http://127.0.0.1:11434/api --name open-webui --restart always ghcr.io/open-webui/open-webui:main
|
||||
docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_BASE_URL=http://127.0.0.1:11434 --name open-webui --restart always ghcr.io/open-webui/open-webui:main
|
||||
```
|
||||
|
||||
### General Connection Errors
|
||||
|
@ -25,8 +25,8 @@ docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_API_BASE_
|
|||
**Troubleshooting Steps**:
|
||||
|
||||
1. **Verify Ollama URL Format**:
|
||||
- When running the Web UI container, ensure the `OLLAMA_API_BASE_URL` is correctly set, including the `/api` suffix. (e.g., `http://192.168.1.1:11434/api` for different host setups).
|
||||
- When running the Web UI container, ensure the `OLLAMA_BASE_URL` is correctly set. (e.g., `http://192.168.1.1:11434` for different host setups).
|
||||
- In the Open WebUI, navigate to "Settings" > "General".
|
||||
- Confirm that the Ollama Server URL is correctly set to `[OLLAMA URL]/api` (e.g., `http://localhost:11434/api`), including the `/api` suffix.
|
||||
- Confirm that the Ollama Server URL is correctly set to `[OLLAMA URL]` (e.g., `http://localhost:11434`).
|
||||
|
||||
By following these enhanced troubleshooting steps, connection issues should be effectively resolved. For further assistance or queries, feel free to reach out to us on our community Discord.
|
||||
|
|
|
@ -15,7 +15,7 @@ import asyncio
|
|||
from apps.web.models.users import Users
|
||||
from constants import ERROR_MESSAGES
|
||||
from utils.utils import decode_token, get_current_user, get_admin_user
|
||||
from config import OLLAMA_BASE_URL, WEBUI_AUTH
|
||||
from config import OLLAMA_BASE_URLS
|
||||
|
||||
from typing import Optional, List, Union
|
||||
|
||||
|
@ -29,8 +29,7 @@ app.add_middleware(
|
|||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
app.state.OLLAMA_BASE_URL = OLLAMA_BASE_URL
|
||||
app.state.OLLAMA_BASE_URLS = [OLLAMA_BASE_URL]
|
||||
app.state.OLLAMA_BASE_URLS = OLLAMA_BASE_URLS
|
||||
app.state.MODELS = {}
|
||||
|
||||
|
||||
|
@ -223,7 +222,7 @@ async def pull_model(
|
|||
r = requests.request(
|
||||
method="POST",
|
||||
url=f"{url}/api/pull",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
stream=True,
|
||||
)
|
||||
|
||||
|
@ -295,7 +294,7 @@ async def push_model(
|
|||
r = requests.request(
|
||||
method="POST",
|
||||
url=f"{url}/api/push",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
)
|
||||
|
||||
r.raise_for_status()
|
||||
|
@ -357,7 +356,7 @@ async def create_model(
|
|||
r = requests.request(
|
||||
method="POST",
|
||||
url=f"{url}/api/create",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
stream=True,
|
||||
)
|
||||
|
||||
|
@ -420,7 +419,7 @@ async def copy_model(
|
|||
r = requests.request(
|
||||
method="POST",
|
||||
url=f"{url}/api/copy",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
)
|
||||
r.raise_for_status()
|
||||
|
||||
|
@ -467,7 +466,7 @@ async def delete_model(
|
|||
r = requests.request(
|
||||
method="DELETE",
|
||||
url=f"{url}/api/delete",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
)
|
||||
r.raise_for_status()
|
||||
|
||||
|
@ -507,7 +506,7 @@ async def show_model_info(form_data: ModelNameForm, user=Depends(get_current_use
|
|||
r = requests.request(
|
||||
method="POST",
|
||||
url=f"{url}/api/show",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
)
|
||||
r.raise_for_status()
|
||||
|
||||
|
@ -559,7 +558,7 @@ async def generate_embeddings(
|
|||
r = requests.request(
|
||||
method="POST",
|
||||
url=f"{url}/api/embeddings",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
)
|
||||
r.raise_for_status()
|
||||
|
||||
|
@ -645,7 +644,7 @@ async def generate_completion(
|
|||
r = requests.request(
|
||||
method="POST",
|
||||
url=f"{url}/api/generate",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
stream=True,
|
||||
)
|
||||
|
||||
|
@ -715,7 +714,7 @@ async def generate_chat_completion(
|
|||
|
||||
r = None
|
||||
|
||||
print(form_data.model_dump_json(exclude_none=True))
|
||||
print(form_data.model_dump_json(exclude_none=True).encode())
|
||||
|
||||
def get_request():
|
||||
nonlocal form_data
|
||||
|
@ -745,7 +744,7 @@ async def generate_chat_completion(
|
|||
r = requests.request(
|
||||
method="POST",
|
||||
url=f"{url}/api/chat",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
stream=True,
|
||||
)
|
||||
|
||||
|
@ -757,6 +756,7 @@ async def generate_chat_completion(
|
|||
headers=dict(r.headers),
|
||||
)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
raise e
|
||||
|
||||
try:
|
||||
|
@ -844,7 +844,7 @@ async def generate_openai_chat_completion(
|
|||
r = requests.request(
|
||||
method="POST",
|
||||
url=f"{url}/v1/chat/completions",
|
||||
data=form_data.model_dump_json(exclude_none=True),
|
||||
data=form_data.model_dump_json(exclude_none=True).encode(),
|
||||
stream=True,
|
||||
)
|
||||
|
||||
|
|
|
@ -3,7 +3,10 @@ from fastapi.middleware.cors import CORSMiddleware
|
|||
from fastapi.responses import StreamingResponse, JSONResponse, FileResponse
|
||||
|
||||
import requests
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
|
@ -15,7 +18,9 @@ from utils.utils import (
|
|||
get_verified_user,
|
||||
get_admin_user,
|
||||
)
|
||||
from config import OPENAI_API_BASE_URL, OPENAI_API_KEY, CACHE_DIR
|
||||
from config import OPENAI_API_BASE_URLS, OPENAI_API_KEYS, CACHE_DIR
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
@ -29,116 +34,207 @@ app.add_middleware(
|
|||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
app.state.OPENAI_API_BASE_URL = OPENAI_API_BASE_URL
|
||||
app.state.OPENAI_API_KEY = OPENAI_API_KEY
|
||||
app.state.OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS
|
||||
app.state.OPENAI_API_KEYS = OPENAI_API_KEYS
|
||||
|
||||
app.state.MODELS = {}
|
||||
|
||||
|
||||
class UrlUpdateForm(BaseModel):
|
||||
url: str
|
||||
@app.middleware("http")
|
||||
async def check_url(request: Request, call_next):
|
||||
if len(app.state.MODELS) == 0:
|
||||
await get_all_models()
|
||||
else:
|
||||
pass
|
||||
|
||||
response = await call_next(request)
|
||||
return response
|
||||
|
||||
|
||||
class KeyUpdateForm(BaseModel):
|
||||
key: str
|
||||
class UrlsUpdateForm(BaseModel):
|
||||
urls: List[str]
|
||||
|
||||
|
||||
@app.get("/url")
|
||||
async def get_openai_url(user=Depends(get_admin_user)):
|
||||
return {"OPENAI_API_BASE_URL": app.state.OPENAI_API_BASE_URL}
|
||||
class KeysUpdateForm(BaseModel):
|
||||
keys: List[str]
|
||||
|
||||
|
||||
@app.post("/url/update")
|
||||
async def update_openai_url(form_data: UrlUpdateForm, user=Depends(get_admin_user)):
|
||||
app.state.OPENAI_API_BASE_URL = form_data.url
|
||||
return {"OPENAI_API_BASE_URL": app.state.OPENAI_API_BASE_URL}
|
||||
@app.get("/urls")
|
||||
async def get_openai_urls(user=Depends(get_admin_user)):
|
||||
return {"OPENAI_API_BASE_URLS": app.state.OPENAI_API_BASE_URLS}
|
||||
|
||||
|
||||
@app.get("/key")
|
||||
async def get_openai_key(user=Depends(get_admin_user)):
|
||||
return {"OPENAI_API_KEY": app.state.OPENAI_API_KEY}
|
||||
@app.post("/urls/update")
|
||||
async def update_openai_urls(form_data: UrlsUpdateForm, user=Depends(get_admin_user)):
|
||||
app.state.OPENAI_API_BASE_URLS = form_data.urls
|
||||
return {"OPENAI_API_BASE_URLS": app.state.OPENAI_API_BASE_URLS}
|
||||
|
||||
|
||||
@app.post("/key/update")
|
||||
async def update_openai_key(form_data: KeyUpdateForm, user=Depends(get_admin_user)):
|
||||
app.state.OPENAI_API_KEY = form_data.key
|
||||
return {"OPENAI_API_KEY": app.state.OPENAI_API_KEY}
|
||||
@app.get("/keys")
|
||||
async def get_openai_keys(user=Depends(get_admin_user)):
|
||||
return {"OPENAI_API_KEYS": app.state.OPENAI_API_KEYS}
|
||||
|
||||
|
||||
@app.post("/keys/update")
|
||||
async def update_openai_key(form_data: KeysUpdateForm, user=Depends(get_admin_user)):
|
||||
app.state.OPENAI_API_KEYS = form_data.keys
|
||||
return {"OPENAI_API_KEYS": app.state.OPENAI_API_KEYS}
|
||||
|
||||
|
||||
@app.post("/audio/speech")
|
||||
async def speech(request: Request, user=Depends(get_verified_user)):
|
||||
target_url = f"{app.state.OPENAI_API_BASE_URL}/audio/speech"
|
||||
|
||||
if app.state.OPENAI_API_KEY == "":
|
||||
raise HTTPException(status_code=401, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND)
|
||||
|
||||
body = await request.body()
|
||||
|
||||
name = hashlib.sha256(body).hexdigest()
|
||||
|
||||
SPEECH_CACHE_DIR = Path(CACHE_DIR).joinpath("./audio/speech/")
|
||||
SPEECH_CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
file_path = SPEECH_CACHE_DIR.joinpath(f"{name}.mp3")
|
||||
file_body_path = SPEECH_CACHE_DIR.joinpath(f"{name}.json")
|
||||
|
||||
# Check if the file already exists in the cache
|
||||
if file_path.is_file():
|
||||
return FileResponse(file_path)
|
||||
|
||||
headers = {}
|
||||
headers["Authorization"] = f"Bearer {app.state.OPENAI_API_KEY}"
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
idx = None
|
||||
try:
|
||||
print("openai")
|
||||
r = requests.post(
|
||||
url=target_url,
|
||||
data=body,
|
||||
headers=headers,
|
||||
stream=True,
|
||||
idx = app.state.OPENAI_API_BASE_URLS.index("https://api.openai.com/v1")
|
||||
body = await request.body()
|
||||
name = hashlib.sha256(body).hexdigest()
|
||||
|
||||
SPEECH_CACHE_DIR = Path(CACHE_DIR).joinpath("./audio/speech/")
|
||||
SPEECH_CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||
file_path = SPEECH_CACHE_DIR.joinpath(f"{name}.mp3")
|
||||
file_body_path = SPEECH_CACHE_DIR.joinpath(f"{name}.json")
|
||||
|
||||
# Check if the file already exists in the cache
|
||||
if file_path.is_file():
|
||||
return FileResponse(file_path)
|
||||
|
||||
headers = {}
|
||||
headers["Authorization"] = f"Bearer {app.state.OPENAI_API_KEYS[idx]}"
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
try:
|
||||
r = requests.post(
|
||||
url=f"{app.state.OPENAI_API_BASE_URLS[idx]}/audio/speech",
|
||||
data=body,
|
||||
headers=headers,
|
||||
stream=True,
|
||||
)
|
||||
|
||||
r.raise_for_status()
|
||||
|
||||
# Save the streaming content to a file
|
||||
with open(file_path, "wb") as f:
|
||||
for chunk in r.iter_content(chunk_size=8192):
|
||||
f.write(chunk)
|
||||
|
||||
with open(file_body_path, "w") as f:
|
||||
json.dump(json.loads(body.decode("utf-8")), f)
|
||||
|
||||
# Return the saved file
|
||||
return FileResponse(file_path)
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
error_detail = "Open WebUI: Server Connection Error"
|
||||
if r is not None:
|
||||
try:
|
||||
res = r.json()
|
||||
if "error" in res:
|
||||
error_detail = f"External: {res['error']}"
|
||||
except:
|
||||
error_detail = f"External: {e}"
|
||||
|
||||
raise HTTPException(status_code=r.status_code, detail=error_detail)
|
||||
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=401, detail=ERROR_MESSAGES.OPENAI_NOT_FOUND)
|
||||
|
||||
|
||||
async def fetch_url(url, key):
|
||||
try:
|
||||
headers = {"Authorization": f"Bearer {key}"}
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, headers=headers) as response:
|
||||
return await response.json()
|
||||
except Exception as e:
|
||||
# Handle connection error here
|
||||
print(f"Connection error: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def merge_models_lists(model_lists):
|
||||
merged_list = []
|
||||
|
||||
for idx, models in enumerate(model_lists):
|
||||
merged_list.extend(
|
||||
[
|
||||
{**model, "urlIdx": idx}
|
||||
for model in models
|
||||
if "api.openai.com" not in app.state.OPENAI_API_BASE_URLS[idx]
|
||||
or "gpt" in model["id"]
|
||||
]
|
||||
)
|
||||
|
||||
r.raise_for_status()
|
||||
return merged_list
|
||||
|
||||
# Save the streaming content to a file
|
||||
with open(file_path, "wb") as f:
|
||||
for chunk in r.iter_content(chunk_size=8192):
|
||||
f.write(chunk)
|
||||
|
||||
with open(file_body_path, "w") as f:
|
||||
json.dump(json.loads(body.decode("utf-8")), f)
|
||||
async def get_all_models():
|
||||
print("get_all_models")
|
||||
tasks = [
|
||||
fetch_url(f"{url}/models", app.state.OPENAI_API_KEYS[idx])
|
||||
for idx, url in enumerate(app.state.OPENAI_API_BASE_URLS)
|
||||
]
|
||||
responses = await asyncio.gather(*tasks)
|
||||
responses = list(filter(lambda x: x is not None and "error" not in x, responses))
|
||||
models = {
|
||||
"data": merge_models_lists(
|
||||
list(map(lambda response: response["data"], responses))
|
||||
)
|
||||
}
|
||||
app.state.MODELS = {model["id"]: model for model in models["data"]}
|
||||
|
||||
# Return the saved file
|
||||
return FileResponse(file_path)
|
||||
return models
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
error_detail = "Open WebUI: Server Connection Error"
|
||||
if r is not None:
|
||||
try:
|
||||
res = r.json()
|
||||
if "error" in res:
|
||||
error_detail = f"External: {res['error']}"
|
||||
except:
|
||||
error_detail = f"External: {e}"
|
||||
|
||||
raise HTTPException(status_code=r.status_code, detail=error_detail)
|
||||
# , user=Depends(get_current_user)
|
||||
@app.get("/models")
|
||||
@app.get("/models/{url_idx}")
|
||||
async def get_models(url_idx: Optional[int] = None):
|
||||
if url_idx == None:
|
||||
return await get_all_models()
|
||||
else:
|
||||
url = app.state.OPENAI_API_BASE_URLS[url_idx]
|
||||
try:
|
||||
r = requests.request(method="GET", url=f"{url}/models")
|
||||
r.raise_for_status()
|
||||
|
||||
response_data = r.json()
|
||||
if "api.openai.com" in url:
|
||||
response_data["data"] = list(
|
||||
filter(lambda model: "gpt" in model["id"], response_data["data"])
|
||||
)
|
||||
|
||||
return response_data
|
||||
except Exception as e:
|
||||
print(e)
|
||||
error_detail = "Open WebUI: Server Connection Error"
|
||||
if r is not None:
|
||||
try:
|
||||
res = r.json()
|
||||
if "error" in res:
|
||||
error_detail = f"External: {res['error']}"
|
||||
except:
|
||||
error_detail = f"External: {e}"
|
||||
|
||||
raise HTTPException(
|
||||
status_code=r.status_code if r else 500,
|
||||
detail=error_detail,
|
||||
)
|
||||
|
||||
|
||||
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
|
||||
async def proxy(path: str, request: Request, user=Depends(get_verified_user)):
|
||||
target_url = f"{app.state.OPENAI_API_BASE_URL}/{path}"
|
||||
print(target_url, app.state.OPENAI_API_KEY)
|
||||
|
||||
if app.state.OPENAI_API_KEY == "":
|
||||
raise HTTPException(status_code=401, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND)
|
||||
idx = 0
|
||||
|
||||
body = await request.body()
|
||||
|
||||
# TODO: Remove below after gpt-4-vision fix from Open AI
|
||||
# Try to decode the body of the request from bytes to a UTF-8 string (Require add max_token to fix gpt-4-vision)
|
||||
try:
|
||||
body = body.decode("utf-8")
|
||||
body = json.loads(body)
|
||||
|
||||
idx = app.state.MODELS[body.get("model")]["urlIdx"]
|
||||
|
||||
# Check if the model is "gpt-4-vision-preview" and set "max_tokens" to 4000
|
||||
# This is a workaround until OpenAI fixes the issue with this model
|
||||
if body.get("model") == "gpt-4-vision-preview":
|
||||
|
@ -158,8 +254,16 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)):
|
|||
except json.JSONDecodeError as e:
|
||||
print("Error loading request body into a dictionary:", e)
|
||||
|
||||
url = app.state.OPENAI_API_BASE_URLS[idx]
|
||||
key = app.state.OPENAI_API_KEYS[idx]
|
||||
|
||||
target_url = f"{url}/{path}"
|
||||
|
||||
if key == "":
|
||||
raise HTTPException(status_code=401, detail=ERROR_MESSAGES.API_KEY_NOT_FOUND)
|
||||
|
||||
headers = {}
|
||||
headers["Authorization"] = f"Bearer {app.state.OPENAI_API_KEY}"
|
||||
headers["Authorization"] = f"Bearer {key}"
|
||||
headers["Content-Type"] = "application/json"
|
||||
|
||||
try:
|
||||
|
@ -181,21 +285,7 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)):
|
|||
headers=dict(r.headers),
|
||||
)
|
||||
else:
|
||||
# For non-SSE, read the response and return it
|
||||
# response_data = (
|
||||
# r.json()
|
||||
# if r.headers.get("Content-Type", "")
|
||||
# == "application/json"
|
||||
# else r.text
|
||||
# )
|
||||
|
||||
response_data = r.json()
|
||||
|
||||
if "api.openai.com" in app.state.OPENAI_API_BASE_URL and path == "models":
|
||||
response_data["data"] = list(
|
||||
filter(lambda model: "gpt" in model["id"], response_data["data"])
|
||||
)
|
||||
|
||||
return response_data
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
|
|
@ -425,7 +425,7 @@ def get_loader(filename: str, file_content_type: str, file_path: str):
|
|||
]
|
||||
|
||||
if file_ext == "pdf":
|
||||
loader = PyPDFLoader(file_path)
|
||||
loader = PyPDFLoader(file_path, extract_images=True)
|
||||
elif file_ext == "csv":
|
||||
loader = CSVLoader(file_path)
|
||||
elif file_ext == "rst":
|
||||
|
|
|
@ -14,7 +14,7 @@ import json
|
|||
from utils.utils import get_admin_user
|
||||
from utils.misc import calculate_sha256, get_gravatar_url
|
||||
|
||||
from config import OLLAMA_API_BASE_URL, DATA_DIR, UPLOAD_DIR
|
||||
from config import OLLAMA_BASE_URLS, DATA_DIR, UPLOAD_DIR
|
||||
from constants import ERROR_MESSAGES
|
||||
|
||||
|
||||
|
@ -75,7 +75,7 @@ async def download_file_stream(url, file_path, file_name, chunk_size=1024 * 1024
|
|||
hashed = calculate_sha256(file)
|
||||
file.seek(0)
|
||||
|
||||
url = f"{OLLAMA_API_BASE_URL}/blobs/sha256:{hashed}"
|
||||
url = f"{OLLAMA_BASE_URLS[0]}/blobs/sha256:{hashed}"
|
||||
response = requests.post(url, data=file)
|
||||
|
||||
if response.ok:
|
||||
|
@ -147,7 +147,7 @@ def upload(file: UploadFile = File(...)):
|
|||
hashed = calculate_sha256(f)
|
||||
f.seek(0)
|
||||
|
||||
url = f"{OLLAMA_API_BASE_URL}/blobs/sha256:{hashed}"
|
||||
url = f"{OLLAMA_BASE_URLS[0]}/blobs/sha256:{hashed}"
|
||||
response = requests.post(url, data=f)
|
||||
|
||||
if response.ok:
|
||||
|
|
|
@ -200,27 +200,32 @@ if not os.path.exists(LITELLM_CONFIG_PATH):
|
|||
|
||||
|
||||
####################################
|
||||
# OLLAMA_API_BASE_URL
|
||||
# OLLAMA_BASE_URL
|
||||
####################################
|
||||
|
||||
OLLAMA_API_BASE_URL = os.environ.get(
|
||||
"OLLAMA_API_BASE_URL", "http://localhost:11434/api"
|
||||
)
|
||||
|
||||
if ENV == "prod":
|
||||
if OLLAMA_API_BASE_URL == "/ollama/api":
|
||||
OLLAMA_API_BASE_URL = "http://host.docker.internal:11434/api"
|
||||
|
||||
|
||||
OLLAMA_BASE_URL = os.environ.get("OLLAMA_BASE_URL", "")
|
||||
|
||||
if OLLAMA_BASE_URL == "":
|
||||
if ENV == "prod":
|
||||
if OLLAMA_BASE_URL == "/ollama":
|
||||
OLLAMA_BASE_URL = "http://host.docker.internal:11434"
|
||||
|
||||
|
||||
if OLLAMA_BASE_URL == "" and OLLAMA_API_BASE_URL != "":
|
||||
OLLAMA_BASE_URL = (
|
||||
OLLAMA_API_BASE_URL[:-4]
|
||||
if OLLAMA_API_BASE_URL.endswith("/api")
|
||||
else OLLAMA_API_BASE_URL
|
||||
)
|
||||
|
||||
OLLAMA_BASE_URLS = os.environ.get("OLLAMA_BASE_URLS", "")
|
||||
OLLAMA_BASE_URLS = OLLAMA_BASE_URLS if OLLAMA_BASE_URLS != "" else OLLAMA_BASE_URL
|
||||
|
||||
OLLAMA_BASE_URLS = [url.strip() for url in OLLAMA_BASE_URLS.split(";")]
|
||||
|
||||
|
||||
####################################
|
||||
# OPENAI_API
|
||||
|
@ -229,9 +234,25 @@ if OLLAMA_BASE_URL == "":
|
|||
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "")
|
||||
OPENAI_API_BASE_URL = os.environ.get("OPENAI_API_BASE_URL", "")
|
||||
|
||||
if OPENAI_API_KEY == "":
|
||||
OPENAI_API_KEY = "none"
|
||||
|
||||
if OPENAI_API_BASE_URL == "":
|
||||
OPENAI_API_BASE_URL = "https://api.openai.com/v1"
|
||||
|
||||
OPENAI_API_KEYS = os.environ.get("OPENAI_API_KEYS", "")
|
||||
OPENAI_API_KEYS = OPENAI_API_KEYS if OPENAI_API_KEYS != "" else OPENAI_API_KEY
|
||||
|
||||
OPENAI_API_KEYS = [url.strip() for url in OPENAI_API_KEYS.split(";")]
|
||||
|
||||
|
||||
OPENAI_API_BASE_URLS = os.environ.get("OPENAI_API_BASE_URLS", "")
|
||||
OPENAI_API_BASE_URLS = (
|
||||
OPENAI_API_BASE_URLS if OPENAI_API_BASE_URLS != "" else OPENAI_API_BASE_URL
|
||||
)
|
||||
|
||||
OPENAI_API_BASE_URLS = [url.strip() for url in OPENAI_API_BASE_URL.split(";")]
|
||||
|
||||
|
||||
####################################
|
||||
# WEBUI
|
||||
|
|
|
@ -41,6 +41,7 @@ class ERROR_MESSAGES(str, Enum):
|
|||
NOT_FOUND = "We could not find what you're looking for :/"
|
||||
USER_NOT_FOUND = "We could not find what you're looking for :/"
|
||||
API_KEY_NOT_FOUND = "Oops! It looks like there's a hiccup. The API key is missing. Please make sure to provide a valid API key to access this feature."
|
||||
|
||||
MALICIOUS = "Unusual activities detected, please try again in a few minutes."
|
||||
|
||||
PANDOC_NOT_INSTALLED = "Pandoc is not installed on the server. Please contact your administrator for assistance."
|
||||
|
@ -50,3 +51,4 @@ class ERROR_MESSAGES(str, Enum):
|
|||
RATE_LIMIT_EXCEEDED = "API rate limit exceeded"
|
||||
|
||||
MODEL_NOT_FOUND = lambda name="": f"Model '{name}' was not found"
|
||||
OPENAI_NOT_FOUND = lambda name="": f"OpenAI API was not found"
|
||||
|
|
|
@ -35,6 +35,9 @@ openpyxl
|
|||
pyxlsb
|
||||
xlrd
|
||||
|
||||
opencv-python-headless
|
||||
rapidocr-onnxruntime
|
||||
|
||||
faster-whisper
|
||||
|
||||
PyJWT
|
||||
|
|
|
@ -14,7 +14,7 @@ services:
|
|||
build:
|
||||
context: .
|
||||
args:
|
||||
OLLAMA_API_BASE_URL: '/ollama/api'
|
||||
OLLAMA_BASE_URL: '/ollama'
|
||||
dockerfile: Dockerfile
|
||||
image: ghcr.io/open-webui/open-webui:main
|
||||
container_name: open-webui
|
||||
|
@ -25,7 +25,7 @@ services:
|
|||
ports:
|
||||
- ${OPEN_WEBUI_PORT-3000}:8080
|
||||
environment:
|
||||
- 'OLLAMA_API_BASE_URL=http://ollama:11434/api'
|
||||
- 'OLLAMA_BASE_URL=http://ollama:11434'
|
||||
- 'WEBUI_SECRET_KEY='
|
||||
extra_hosts:
|
||||
- host.docker.internal:host-gateway
|
||||
|
|
38
i18next-parser.config.ts
Normal file
38
i18next-parser.config.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
// i18next-parser.config.ts
|
||||
import { getLanguages } from './src/lib/i18n/index.ts';
|
||||
|
||||
const getLangCodes = async () => {
|
||||
const languages = await getLanguages();
|
||||
return languages.map((l) => l.code);
|
||||
};
|
||||
|
||||
export default {
|
||||
contextSeparator: '_',
|
||||
createOldCatalogs: false,
|
||||
defaultNamespace: 'translation',
|
||||
defaultValue: '',
|
||||
indentation: 2,
|
||||
keepRemoved: false,
|
||||
keySeparator: false,
|
||||
lexers: {
|
||||
svelte: ['JavascriptLexer'],
|
||||
js: ['JavascriptLexer'], // if you're writing jsx inside .js files, change this to JsxLexer
|
||||
ts: ['JavascriptLexer'],
|
||||
|
||||
default: ['JavascriptLexer']
|
||||
},
|
||||
lineEnding: 'auto',
|
||||
locales: await getLangCodes(),
|
||||
namespaceSeparator: false,
|
||||
output: 'src/lib/i18n/locales/$LOCALE/$NAMESPACE.json',
|
||||
pluralSeparator: '_',
|
||||
input: 'src/**/*.{js,svelte}',
|
||||
sort: true,
|
||||
verbose: true,
|
||||
failOnWarnings: false,
|
||||
failOnUpdate: false,
|
||||
customValueTemplate: null,
|
||||
resetDefaultValueLocale: null,
|
||||
i18nextOptions: null,
|
||||
yamlOptions: null
|
||||
};
|
|
@ -40,7 +40,7 @@ spec:
|
|||
- name: data
|
||||
mountPath: /app/backend/data
|
||||
env:
|
||||
- name: OLLAMA_API_BASE_URL
|
||||
- name: OLLAMA_BASE_URL
|
||||
value: {{ include "ollama.url" . | quote }}
|
||||
tty: true
|
||||
{{- with .Values.webui.nodeSelector }}
|
||||
|
|
|
@ -26,8 +26,8 @@ spec:
|
|||
cpu: "1000m"
|
||||
memory: "1Gi"
|
||||
env:
|
||||
- name: OLLAMA_API_BASE_URL
|
||||
value: "http://ollama-service.open-webui.svc.cluster.local:11434/api"
|
||||
- name: OLLAMA_BASE_URL
|
||||
value: "http://ollama-service.open-webui.svc.cluster.local:11434"
|
||||
tty: true
|
||||
volumeMounts:
|
||||
- name: webui-volume
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "open-webui",
|
||||
"version": "0.1.108",
|
||||
"version": "0.1.110",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev --host",
|
||||
|
@ -27,6 +27,7 @@
|
|||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-svelte": "^2.30.0",
|
||||
"i18next-parser": "^8.13.0",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^2.8.0",
|
||||
"prettier-plugin-svelte": "^2.10.1",
|
||||
|
|
|
@ -43,6 +43,10 @@ ol > li {
|
|||
font-weight: 400;
|
||||
}
|
||||
|
||||
li p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
--tw-border-opacity: 1;
|
||||
background-color: rgba(217, 217, 227, 0.8);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { OPENAI_API_BASE_URL } from '$lib/constants';
|
||||
|
||||
export const getOpenAIUrl = async (token: string = '') => {
|
||||
export const getOpenAIUrls = async (token: string = '') => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${OPENAI_API_BASE_URL}/url`, {
|
||||
const res = await fetch(`${OPENAI_API_BASE_URL}/urls`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
|
@ -29,13 +29,13 @@ export const getOpenAIUrl = async (token: string = '') => {
|
|||
throw error;
|
||||
}
|
||||
|
||||
return res.OPENAI_API_BASE_URL;
|
||||
return res.OPENAI_API_BASE_URLS;
|
||||
};
|
||||
|
||||
export const updateOpenAIUrl = async (token: string = '', url: string) => {
|
||||
export const updateOpenAIUrls = async (token: string = '', urls: string[]) => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${OPENAI_API_BASE_URL}/url/update`, {
|
||||
const res = await fetch(`${OPENAI_API_BASE_URL}/urls/update`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
|
@ -43,7 +43,7 @@ export const updateOpenAIUrl = async (token: string = '', url: string) => {
|
|||
...(token && { authorization: `Bearer ${token}` })
|
||||
},
|
||||
body: JSON.stringify({
|
||||
url: url
|
||||
urls: urls
|
||||
})
|
||||
})
|
||||
.then(async (res) => {
|
||||
|
@ -64,13 +64,13 @@ export const updateOpenAIUrl = async (token: string = '', url: string) => {
|
|||
throw error;
|
||||
}
|
||||
|
||||
return res.OPENAI_API_BASE_URL;
|
||||
return res.OPENAI_API_BASE_URLS;
|
||||
};
|
||||
|
||||
export const getOpenAIKey = async (token: string = '') => {
|
||||
export const getOpenAIKeys = async (token: string = '') => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${OPENAI_API_BASE_URL}/key`, {
|
||||
const res = await fetch(`${OPENAI_API_BASE_URL}/keys`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
|
@ -96,13 +96,13 @@ export const getOpenAIKey = async (token: string = '') => {
|
|||
throw error;
|
||||
}
|
||||
|
||||
return res.OPENAI_API_KEY;
|
||||
return res.OPENAI_API_KEYS;
|
||||
};
|
||||
|
||||
export const updateOpenAIKey = async (token: string = '', key: string) => {
|
||||
export const updateOpenAIKeys = async (token: string = '', keys: string[]) => {
|
||||
let error = null;
|
||||
|
||||
const res = await fetch(`${OPENAI_API_BASE_URL}/key/update`, {
|
||||
const res = await fetch(`${OPENAI_API_BASE_URL}/keys/update`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
|
@ -110,7 +110,7 @@ export const updateOpenAIKey = async (token: string = '', key: string) => {
|
|||
...(token && { authorization: `Bearer ${token}` })
|
||||
},
|
||||
body: JSON.stringify({
|
||||
key: key
|
||||
keys: keys
|
||||
})
|
||||
})
|
||||
.then(async (res) => {
|
||||
|
@ -131,7 +131,7 @@ export const updateOpenAIKey = async (token: string = '', key: string) => {
|
|||
throw error;
|
||||
}
|
||||
|
||||
return res.OPENAI_API_KEY;
|
||||
return res.OPENAI_API_KEYS;
|
||||
};
|
||||
|
||||
export const getOpenAIModels = async (token: string = '') => {
|
||||
|
|
|
@ -225,33 +225,80 @@
|
|||
}, 100);
|
||||
};
|
||||
|
||||
// TODO: change delete behaviour
|
||||
// const deleteMessageAndDescendants = async (messageId: string) => {
|
||||
// if (history.messages[messageId]) {
|
||||
// history.messages[messageId].deleted = true;
|
||||
|
||||
// for (const childId of history.messages[messageId].childrenIds) {
|
||||
// await deleteMessageAndDescendants(childId);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// const triggerDeleteMessageRecursive = async (messageId: string) => {
|
||||
// await deleteMessageAndDescendants(messageId);
|
||||
// await updateChatById(localStorage.token, chatId, { history });
|
||||
// await chats.set(await getChatList(localStorage.token));
|
||||
// };
|
||||
|
||||
const messageDeleteHandler = async (messageId) => {
|
||||
if (history.messages[messageId]) {
|
||||
history.messages[messageId].deleted = true;
|
||||
|
||||
for (const childId of history.messages[messageId].childrenIds) {
|
||||
history.messages[childId].deleted = true;
|
||||
const messageToDelete = history.messages[messageId];
|
||||
const messageParentId = messageToDelete.parentId;
|
||||
const messageChildrenIds = messageToDelete.childrenIds ?? [];
|
||||
const hasSibling = messageChildrenIds.some(
|
||||
(childId) => history.messages[childId]?.childrenIds?.length > 0
|
||||
);
|
||||
messageChildrenIds.forEach((childId) => {
|
||||
const child = history.messages[childId];
|
||||
if (child && child.childrenIds) {
|
||||
if (child.childrenIds.length === 0 && !hasSibling) {
|
||||
// if last prompt/response pair
|
||||
history.messages[messageParentId].childrenIds = [];
|
||||
history.currentId = messageParentId;
|
||||
} else {
|
||||
child.childrenIds.forEach((grandChildId) => {
|
||||
if (history.messages[grandChildId]) {
|
||||
history.messages[grandChildId].parentId = messageParentId;
|
||||
history.messages[messageParentId].childrenIds.push(grandChildId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
await updateChatById(localStorage.token, chatId, { history });
|
||||
// remove response
|
||||
history.messages[messageParentId].childrenIds = history.messages[
|
||||
messageParentId
|
||||
].childrenIds.filter((id) => id !== childId);
|
||||
});
|
||||
// remove prompt
|
||||
history.messages[messageParentId].childrenIds = history.messages[
|
||||
messageParentId
|
||||
].childrenIds.filter((id) => id !== messageId);
|
||||
await updateChatById(localStorage.token, chatId, {
|
||||
messages: messages,
|
||||
history: history
|
||||
});
|
||||
};
|
||||
|
||||
// const messageDeleteHandler = async (messageId) => {
|
||||
// const message = history.messages[messageId];
|
||||
// const parentId = message.parentId;
|
||||
// const childrenIds = message.childrenIds ?? [];
|
||||
// const grandchildrenIds = [];
|
||||
|
||||
// // Iterate through childrenIds to find grandchildrenIds
|
||||
// for (const childId of childrenIds) {
|
||||
// const childMessage = history.messages[childId];
|
||||
// const grandChildrenIds = childMessage.childrenIds ?? [];
|
||||
|
||||
// for (const grandchildId of grandchildrenIds) {
|
||||
// const childMessage = history.messages[grandchildId];
|
||||
// childMessage.parentId = parentId;
|
||||
// }
|
||||
// grandchildrenIds.push(...grandChildrenIds);
|
||||
// }
|
||||
|
||||
// history.messages[parentId].childrenIds.push(...grandchildrenIds);
|
||||
// history.messages[parentId].childrenIds = history.messages[parentId].childrenIds.filter(
|
||||
// (id) => id !== messageId
|
||||
// );
|
||||
|
||||
// // Select latest message
|
||||
// let currentMessageId = grandchildrenIds.at(-1);
|
||||
// if (currentMessageId) {
|
||||
// let messageChildrenIds = history.messages[currentMessageId].childrenIds;
|
||||
// while (messageChildrenIds.length !== 0) {
|
||||
// currentMessageId = messageChildrenIds.at(-1);
|
||||
// messageChildrenIds = history.messages[currentMessageId].childrenIds;
|
||||
// }
|
||||
// history.currentId = currentMessageId;
|
||||
// }
|
||||
|
||||
// await updateChatById(localStorage.token, chatId, { messages, history });
|
||||
// };
|
||||
</script>
|
||||
|
||||
{#if messages.length == 0}
|
||||
|
@ -260,57 +307,55 @@
|
|||
<div class=" pb-10">
|
||||
{#key chatId}
|
||||
{#each messages as message, messageIdx}
|
||||
{#if !message.deleted}
|
||||
<div class=" w-full">
|
||||
<div
|
||||
class="flex flex-col justify-between px-5 mb-3 {$settings?.fullScreenMode ?? null
|
||||
? 'max-w-full'
|
||||
: 'max-w-3xl'} mx-auto rounded-lg group"
|
||||
>
|
||||
{#if message.role === 'user'}
|
||||
<UserMessage
|
||||
on:delete={() => messageDeleteHandler(message.id)}
|
||||
user={$user}
|
||||
{message}
|
||||
isFirstMessage={messageIdx === 0}
|
||||
siblings={message.parentId !== null
|
||||
? history.messages[message.parentId]?.childrenIds ?? []
|
||||
: Object.values(history.messages)
|
||||
.filter((message) => message.parentId === null)
|
||||
.map((message) => message.id) ?? []}
|
||||
{confirmEditMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{copyToClipboard}
|
||||
/>
|
||||
{:else}
|
||||
<ResponseMessage
|
||||
{message}
|
||||
modelfiles={selectedModelfiles}
|
||||
siblings={history.messages[message.parentId]?.childrenIds ?? []}
|
||||
isLastMessage={messageIdx + 1 === messages.length}
|
||||
{confirmEditResponseMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{rateMessage}
|
||||
{copyToClipboard}
|
||||
{continueGeneration}
|
||||
{regenerateResponse}
|
||||
on:save={async (e) => {
|
||||
console.log('save', e);
|
||||
<div class=" w-full">
|
||||
<div
|
||||
class="flex flex-col justify-between px-5 mb-3 {$settings?.fullScreenMode ?? null
|
||||
? 'max-w-full'
|
||||
: 'max-w-3xl'} mx-auto rounded-lg group"
|
||||
>
|
||||
{#if message.role === 'user'}
|
||||
<UserMessage
|
||||
on:delete={() => messageDeleteHandler(message.id)}
|
||||
user={$user}
|
||||
{message}
|
||||
isFirstMessage={messageIdx === 0}
|
||||
siblings={message.parentId !== null
|
||||
? history.messages[message.parentId]?.childrenIds ?? []
|
||||
: Object.values(history.messages)
|
||||
.filter((message) => message.parentId === null)
|
||||
.map((message) => message.id) ?? []}
|
||||
{confirmEditMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{copyToClipboard}
|
||||
/>
|
||||
{:else}
|
||||
<ResponseMessage
|
||||
{message}
|
||||
modelfiles={selectedModelfiles}
|
||||
siblings={history.messages[message.parentId]?.childrenIds ?? []}
|
||||
isLastMessage={messageIdx + 1 === messages.length}
|
||||
{confirmEditResponseMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{rateMessage}
|
||||
{copyToClipboard}
|
||||
{continueGeneration}
|
||||
{regenerateResponse}
|
||||
on:save={async (e) => {
|
||||
console.log('save', e);
|
||||
|
||||
const message = e.detail;
|
||||
history.messages[message.id] = message;
|
||||
await updateChatById(localStorage.token, chatId, {
|
||||
messages: messages,
|
||||
history: history
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
const message = e.detail;
|
||||
history.messages[message.id] = message;
|
||||
await updateChatById(localStorage.token, chatId, {
|
||||
messages: messages,
|
||||
history: history
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
{#if bottomPadding}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
import CodeBlock from './CodeBlock.svelte';
|
||||
import Image from '$lib/components/common/Image.svelte';
|
||||
import { WEBUI_BASE_URL } from '$lib/constants';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
|
||||
export let modelfiles = [];
|
||||
export let message;
|
||||
|
@ -346,6 +347,7 @@
|
|||
class=" bg-transparent outline-none w-full resize-none"
|
||||
bind:value={editedContent}
|
||||
on:input={(e) => {
|
||||
e.target.style.height = '';
|
||||
e.target.style.height = `${e.target.scrollHeight}px`;
|
||||
}}
|
||||
/>
|
||||
|
@ -464,189 +466,125 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
editMessageHandler();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition copy-response-button"
|
||||
on:click={() => {
|
||||
copyToClipboard(message.content);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded {message.rating === 1
|
||||
? 'bg-gray-100 dark:bg-gray-800'
|
||||
: ''} dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
rateMessage(message.id, 1);
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded {message.rating === -1
|
||||
? 'bg-gray-100 dark:bg-gray-800'
|
||||
: ''} dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
rateMessage(message.id, -1);
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
|
||||
<button
|
||||
id="speak-button-{message.id}"
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
if (!loadingSpeech) {
|
||||
toggleSpeakMessage(message);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if loadingSpeech}
|
||||
<svg
|
||||
class=" w-4 h-4"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
><style>
|
||||
.spinner_S1WN {
|
||||
animation: spinner_MGfb 0.8s linear infinite;
|
||||
animation-delay: -0.8s;
|
||||
}
|
||||
.spinner_Km9P {
|
||||
animation-delay: -0.65s;
|
||||
}
|
||||
.spinner_JApP {
|
||||
animation-delay: -0.5s;
|
||||
}
|
||||
@keyframes spinner_MGfb {
|
||||
93.75%,
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
</style><circle class="spinner_S1WN" cx="4" cy="12" r="3" /><circle
|
||||
class="spinner_S1WN spinner_Km9P"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="3"
|
||||
/><circle class="spinner_S1WN spinner_JApP" cx="20" cy="12" r="3" /></svg
|
||||
>
|
||||
{:else if speaking}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M17.25 9.75 19.5 12m0 0 2.25 2.25M19.5 12l2.25-2.25M19.5 12l-2.25 2.25m-10.5-6 4.72-4.72a.75.75 0 0 1 1.28.53v15.88a.75.75 0 0 1-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.009 9.009 0 0 1 2.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75Z"
|
||||
/>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M19.114 5.636a9 9 0 010 12.728M16.463 8.288a5.25 5.25 0 010 7.424M6.75 8.25l4.72-4.72a.75.75 0 011.28.53v15.88a.75.75 0 01-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.01 9.01 0 012.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75z"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
{#if $config.images}
|
||||
<Tooltip content="Edit" placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
if (!generatingImage) {
|
||||
generateImage(message);
|
||||
editMessageHandler();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content="Copy" placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition copy-response-button"
|
||||
on:click={() => {
|
||||
copyToClipboard(message.content);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content="Good Response" placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded {message.rating === 1
|
||||
? 'bg-gray-100 dark:bg-gray-800'
|
||||
: ''} dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
rateMessage(message.id, 1);
|
||||
}}
|
||||
>
|
||||
<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="Bad Response" placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded {message.rating === -1
|
||||
? 'bg-gray-100 dark:bg-gray-800'
|
||||
: ''} dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
rateMessage(message.id, -1);
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
|
||||
<Tooltip content="Read Aloud" placement="bottom">
|
||||
<button
|
||||
id="speak-button-{message.id}"
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
if (!loadingSpeech) {
|
||||
toggleSpeakMessage(message);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if generatingImage}
|
||||
{#if loadingSpeech}
|
||||
<svg
|
||||
class=" w-4 h-4"
|
||||
fill="currentColor"
|
||||
|
@ -681,6 +619,21 @@
|
|||
r="3"
|
||||
/></svg
|
||||
>
|
||||
{:else if speaking}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M17.25 9.75 19.5 12m0 0 2.25 2.25M19.5 12l2.25-2.25M19.5 12l-2.25 2.25m-10.5-6 4.72-4.72a.75.75 0 0 1 1.28.53v15.88a.75.75 0 0 1-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.009 9.009 0 0 1 2.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75Z"
|
||||
/>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -693,93 +646,166 @@
|
|||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z"
|
||||
d="M19.114 5.636a9 9 0 010 12.728M16.463 8.288a5.25 5.25 0 010 7.424M6.75 8.25l4.72-4.72a.75.75 0 011.28.53v15.88a.75.75 0 01-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.01 9.01 0 012.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75z"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
{#if $config.images}
|
||||
<Tooltip content="Generate Image" placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
if (!generatingImage) {
|
||||
generateImage(message);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if generatingImage}
|
||||
<svg
|
||||
class=" w-4 h-4"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
><style>
|
||||
.spinner_S1WN {
|
||||
animation: spinner_MGfb 0.8s linear infinite;
|
||||
animation-delay: -0.8s;
|
||||
}
|
||||
.spinner_Km9P {
|
||||
animation-delay: -0.65s;
|
||||
}
|
||||
.spinner_JApP {
|
||||
animation-delay: -0.5s;
|
||||
}
|
||||
@keyframes spinner_MGfb {
|
||||
93.75%,
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
</style><circle class="spinner_S1WN" cx="4" cy="12" r="3" /><circle
|
||||
class="spinner_S1WN spinner_Km9P"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="3"
|
||||
/><circle
|
||||
class="spinner_S1WN spinner_JApP"
|
||||
cx="20"
|
||||
cy="12"
|
||||
r="3"
|
||||
/></svg
|
||||
>
|
||||
{:else}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
{#if message.info}
|
||||
<button
|
||||
class=" {isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition whitespace-pre-wrap"
|
||||
on:click={() => {
|
||||
console.log(message);
|
||||
}}
|
||||
id="info-{message.id}"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
<Tooltip content="Generation Info" placement="bottom">
|
||||
<button
|
||||
class=" {isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition whitespace-pre-wrap"
|
||||
on:click={() => {
|
||||
console.log(message);
|
||||
}}
|
||||
id="info-{message.id}"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
{#if isLastMessage}
|
||||
<button
|
||||
type="button"
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition regenerate-response-button"
|
||||
on:click={() => {
|
||||
continueGeneration();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
<Tooltip content="Continue Response" placement="bottom">
|
||||
<button
|
||||
type="button"
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition regenerate-response-button"
|
||||
on:click={() => {
|
||||
continueGeneration();
|
||||
}}
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.91 11.672a.375.375 0 0 1 0 .656l-5.603 3.113a.375.375 0 0 1-.557-.328V8.887c0-.286.307-.466.557-.327l5.603 3.112Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.91 11.672a.375.375 0 0 1 0 .656l-5.603 3.113a.375.375 0 0 1-.557-.328V8.887c0-.286.307-.466.557-.327l5.603 3.112Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition regenerate-response-button"
|
||||
on:click={regenerateResponse}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
<Tooltip content="Regenerate" placement="bottom">
|
||||
<button
|
||||
type="button"
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition regenerate-response-button"
|
||||
on:click={regenerateResponse}
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
import Name from './Name.svelte';
|
||||
import ProfileImage from './ProfileImage.svelte';
|
||||
import { modelfiles, settings } from '$lib/stores';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
|
@ -171,7 +172,8 @@
|
|||
class=" bg-transparent outline-none w-full resize-none"
|
||||
bind:value={editedContent}
|
||||
on:input={(e) => {
|
||||
messageEditTextAreaElement.style.height = `${messageEditTextAreaElement.scrollHeight}px`;
|
||||
e.target.style.height = '';
|
||||
e.target.style.height = `${e.target.scrollHeight}px`;
|
||||
}}
|
||||
/>
|
||||
|
||||
|
@ -248,55 +250,11 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<button
|
||||
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition edit-user-message-button"
|
||||
on:click={() => {
|
||||
editMessageHandler();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
copyToClipboard(message.content);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{#if !isFirstMessage}
|
||||
<Tooltip content="Edit" placement="bottom">
|
||||
<button
|
||||
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition edit-user-message-button"
|
||||
on:click={() => {
|
||||
deleteMessageHandler();
|
||||
editMessageHandler();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
|
@ -310,10 +268,60 @@
|
|||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
|
||||
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content="Copy" placement="bottom">
|
||||
<button
|
||||
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
copyToClipboard(message.content);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
{#if !isFirstMessage}
|
||||
<Tooltip content="Delete" placement="bottom">
|
||||
<button
|
||||
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
deleteMessageHandler();
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
d="M10 2a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 2zM10 15a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 15zM10 7a3 3 0 100 6 3 3 0 000-6zM15.657 5.404a.75.75 0 10-1.06-1.06l-1.061 1.06a.75.75 0 001.06 1.06l1.06-1.06zM6.464 14.596a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 001.06 1.06l1.06-1.06zM18 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 0118 10zM5 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 015 10zM14.596 15.657a.75.75 0 001.06-1.06l-1.06-1.061a.75.75 0 10-1.06 1.06l1.06 1.06zM5.404 6.464a.75.75 0 001.06-1.06l-1.06-1.06a.75.75 0 10-1.061 1.06l1.06 1.06z"
|
||||
/>
|
||||
</svg> -->
|
||||
<span class="ml-2 self-center">{$i18n.t(' JSON ')}</span>
|
||||
<span class="ml-2 self-center">{$i18n.t('JSON')}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,12 @@
|
|||
const dispatch = createEventDispatcher();
|
||||
|
||||
import { getOllamaUrls, getOllamaVersion, updateOllamaUrls } from '$lib/apis/ollama';
|
||||
import { getOpenAIKey, getOpenAIUrl, updateOpenAIKey, updateOpenAIUrl } from '$lib/apis/openai';
|
||||
import {
|
||||
getOpenAIKeys,
|
||||
getOpenAIUrls,
|
||||
updateOpenAIKeys,
|
||||
updateOpenAIUrls
|
||||
} from '$lib/apis/openai';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
@ -18,12 +23,14 @@
|
|||
let OPENAI_API_KEY = '';
|
||||
let OPENAI_API_BASE_URL = '';
|
||||
|
||||
let OPENAI_API_KEYS = [''];
|
||||
let OPENAI_API_BASE_URLS = [''];
|
||||
|
||||
let showOpenAI = false;
|
||||
let showLiteLLM = false;
|
||||
|
||||
const updateOpenAIHandler = async () => {
|
||||
OPENAI_API_BASE_URL = await updateOpenAIUrl(localStorage.token, OPENAI_API_BASE_URL);
|
||||
OPENAI_API_KEY = await updateOpenAIKey(localStorage.token, OPENAI_API_KEY);
|
||||
OPENAI_API_BASE_URLS = await updateOpenAIUrls(localStorage.token, OPENAI_API_BASE_URLS);
|
||||
OPENAI_API_KEYS = await updateOpenAIKeys(localStorage.token, OPENAI_API_KEYS);
|
||||
|
||||
await models.set(await getModels());
|
||||
};
|
||||
|
@ -45,8 +52,8 @@
|
|||
onMount(async () => {
|
||||
if ($user.role === 'admin') {
|
||||
OLLAMA_BASE_URLS = await getOllamaUrls(localStorage.token);
|
||||
OPENAI_API_BASE_URL = await getOpenAIUrl(localStorage.token);
|
||||
OPENAI_API_KEY = await getOpenAIKey(localStorage.token);
|
||||
OPENAI_API_BASE_URLS = await getOpenAIUrls(localStorage.token);
|
||||
OPENAI_API_KEYS = await getOpenAIKeys(localStorage.token);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -73,37 +80,74 @@
|
|||
</div>
|
||||
|
||||
{#if showOpenAI}
|
||||
<div>
|
||||
<div class=" mb-2.5 text-sm font-medium">{$i18n.t('API Key')}</div>
|
||||
<div class="flex w-full">
|
||||
<div class="flex-1">
|
||||
<input
|
||||
class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none"
|
||||
placeholder={$i18n.t('Enter OpenAI API Key')}
|
||||
bind:value={OPENAI_API_KEY}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
{#each OPENAI_API_BASE_URLS as url, idx}
|
||||
<div class="flex w-full gap-2">
|
||||
<div class="flex-1">
|
||||
<input
|
||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
placeholder={$i18n.t('API Base URL')}
|
||||
bind:value={url}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class=" mb-2.5 text-sm font-medium">{$i18n.t('API Base URL')}</div>
|
||||
<div class="flex w-full">
|
||||
<div class="flex-1">
|
||||
<input
|
||||
class="w-full rounded py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none"
|
||||
placeholder="Enter OpenAI API Base URL"
|
||||
bind:value={OPENAI_API_BASE_URL}
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div class="flex-1">
|
||||
<input
|
||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
placeholder={$i18n.t('API Key')}
|
||||
bind:value={OPENAI_API_KEYS[idx]}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
<div class="self-center flex items-center">
|
||||
{#if idx === 0}
|
||||
<button
|
||||
class="px-1"
|
||||
on:click={() => {
|
||||
OPENAI_API_BASE_URLS = [...OPENAI_API_BASE_URLS, ''];
|
||||
OPENAI_API_KEYS = [...OPENAI_API_KEYS, ''];
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
class="px-1"
|
||||
on:click={() => {
|
||||
OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS.filter(
|
||||
(url, urlIdx) => idx !== urlIdx
|
||||
);
|
||||
OPENAI_API_KEYS = OPENAI_API_KEYS.filter((key, keyIdx) => idx !== keyIdx);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path d="M3.75 7.25a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" />
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
|
||||
WebUI will make requests to <span class=" text-gray-200"
|
||||
>'{OPENAI_API_BASE_URL}/chat'</span
|
||||
>
|
||||
</div>
|
||||
<div class=" mb-1 text-xs text-gray-400 dark:text-gray-500">
|
||||
WebUI will make requests to <span class=" text-gray-200">'{url}/models'</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -193,7 +237,7 @@
|
|||
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
|
||||
{$i18n.t('Trouble accessing Ollama?')}
|
||||
<a
|
||||
class=" text-gray-300 font-medium"
|
||||
class=" text-gray-300 font-medium underline"
|
||||
href="https://github.com/open-webui/open-webui#troubleshooting"
|
||||
target="_blank"
|
||||
>
|
||||
|
|
|
@ -149,7 +149,7 @@
|
|||
<br />
|
||||
{$i18n.t('You can help us translate the WebUI.')}
|
||||
<a
|
||||
class=" text-gray-300 font-medium"
|
||||
class=" text-gray-300 font-medium underline"
|
||||
href="https://github.com/open-webui/open-webui/blob/main/docs/CONTRIBUTING.md#-translations-and-internationalization"
|
||||
target="_blank"
|
||||
>
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
let modelUploadMode = 'file';
|
||||
let modelInputFile = '';
|
||||
let modelFileUrl = '';
|
||||
let modelFileContent = `TEMPLATE """{{ .System }}\nUSER: {{ .Prompt }}\nASSSISTANT: """\nPARAMETER num_ctx 4096\nPARAMETER stop "</s>"\nPARAMETER stop "USER:"\nPARAMETER stop "ASSSISTANT:"`;
|
||||
let modelFileContent = `TEMPLATE """{{ .System }}\nUSER: {{ .Prompt }}\nASSISTANT: """\nPARAMETER num_ctx 4096\nPARAMETER stop "</s>"\nPARAMETER stop "USER:"\nPARAMETER stop "ASSISTANT:"`;
|
||||
let modelFileDigest = '';
|
||||
let uploadProgress = null;
|
||||
|
||||
|
@ -517,7 +517,7 @@
|
|||
{#if !deleteModelTag}
|
||||
<option value="" disabled selected>Select a model</option>
|
||||
{/if}
|
||||
{#each $models.filter((m) => m.size != null) as model}
|
||||
{#each $models.filter((m) => m.size != null && (selectedOllamaUrlIdx === null ? true : (m?.urls ?? []).includes(selectedOllamaUrlIdx))) as model}
|
||||
<option value={model.name} class="bg-gray-100 dark:bg-gray-700"
|
||||
>{model.name + ' (' + (model.size / 1024 ** 3).toFixed(1) + ' GB)'}</option
|
||||
>
|
||||
|
@ -599,7 +599,7 @@
|
|||
on:change={() => {
|
||||
console.log(modelInputFile);
|
||||
}}
|
||||
accept=".gguf"
|
||||
accept=".gguf,.safetensors"
|
||||
required
|
||||
hidden
|
||||
/>
|
||||
|
|
|
@ -140,7 +140,9 @@
|
|||
<button
|
||||
class="w-full text-sm font-medium py-3 bg-gray-850 hover:bg-gray-800 text-center rounded-xl"
|
||||
type="button"
|
||||
on:click={uploadDocInputElement.click}
|
||||
on:click={() => {
|
||||
uploadDocInputElement.click();
|
||||
}}
|
||||
>
|
||||
{#if inputFiles}
|
||||
{inputFiles.length > 0 ? `${inputFiles.length}` : ''} document(s) selected.
|
||||
|
|
|
@ -90,8 +90,3 @@ export const SUPPORTED_FILE_EXTENSIONS = [
|
|||
// This feature, akin to $env/static/private, exclusively incorporates environment variables
|
||||
// that are prefixed with config.kit.env.publicPrefix (usually set to PUBLIC_).
|
||||
// Consequently, these variables can be securely exposed to client-side code.
|
||||
|
||||
// Example of the .env configuration:
|
||||
// OLLAMA_API_BASE_URL="http://localhost:11434/api"
|
||||
// # Public
|
||||
// PUBLIC_API_BASE_URL=$OLLAMA_API_BASE_URL
|
||||
|
|
|
@ -4,7 +4,7 @@ import LanguageDetector from 'i18next-browser-languagedetector';
|
|||
import type { i18n as i18nType } from 'i18next';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
const createI18nStore = (i18n: i18n) => {
|
||||
const createI18nStore = (i18n: i18nType) => {
|
||||
const i18nWritable = writable(i18n);
|
||||
|
||||
i18n.on('initialized', () => {
|
||||
|
@ -20,7 +20,7 @@ const createI18nStore = (i18n: i18n) => {
|
|||
return i18nWritable;
|
||||
};
|
||||
|
||||
const createIsLoadingStore = (i18n: i18n) => {
|
||||
const createIsLoadingStore = (i18n: i18nType) => {
|
||||
const isLoading = writable(false);
|
||||
|
||||
// if loaded resources are empty || {}, set loading to true
|
||||
|
@ -39,11 +39,13 @@ const createIsLoadingStore = (i18n: i18n) => {
|
|||
|
||||
i18next
|
||||
.use(
|
||||
resourcesToBackend((language, namespace) => import(`./locales/${language}/${namespace}.json`))
|
||||
resourcesToBackend(
|
||||
(language: string, namespace: string) => import(`./locales/${language}/${namespace}.json`)
|
||||
)
|
||||
)
|
||||
.use(LanguageDetector)
|
||||
.init({
|
||||
debug: true,
|
||||
debug: false,
|
||||
detection: {
|
||||
order: ['querystring', 'localStorage', 'navigator'],
|
||||
caches: ['localStorage'],
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
"Add message": "Nachricht eingeben",
|
||||
"add tags": "Tags hinzufügen",
|
||||
"Adjusting these settings will apply changes universally to all users.": "Das Anpassen dieser Einstellungen wirkt sich universell auf alle Benutzer aus.",
|
||||
"admin": "Administrator",
|
||||
"Admin": "",
|
||||
"Admin Panel": "Admin Panel",
|
||||
"Admin Settings": "Admin Einstellungen",
|
||||
"Advanced": "Angepasst",
|
||||
"Advanced Model Params": "Erweiterte Modell Parameter",
|
||||
"Advanced Parameters": "Erweiterte Parameter",
|
||||
"all": "Alle",
|
||||
|
@ -35,7 +34,6 @@
|
|||
"API Key": "API Key",
|
||||
"API RPM": "API RPM",
|
||||
"are allowed - Activate this command by typing": "sind erlaubt - Aktiviere diesen Befehl, indem du",
|
||||
"assistant": "Assistent",
|
||||
"Audio": "Audio",
|
||||
"Auto-playback response": "Automatische Wiedergabe der Antwort",
|
||||
"Auto-send input after 3 sec.": "Automatisches Senden der Eingabe nach 3 Sek",
|
||||
|
@ -98,7 +96,7 @@
|
|||
"Deleted {tagName}": "{tagName} gelöscht",
|
||||
"Description": "Beschreibung",
|
||||
"Desktop Notifications": "Desktop-Benachrichtigungen",
|
||||
"Didn't find your language?": "Deine Sprache nicht gefunden?",
|
||||
"Didn't find your language?": "Deine Sprache nicht vorhanden?",
|
||||
"Disabled": "Deaktiviert",
|
||||
"Discover a modelfile": "Eine Modelfiles entdecken",
|
||||
"Discover a prompt": "Einen Prompt entdecken",
|
||||
|
@ -121,21 +119,17 @@
|
|||
"Enable Chat History": "Chat-Verlauf aktivieren",
|
||||
"Enable New Sign Ups": "Neue Anmeldungen aktivieren",
|
||||
"Enabled": "Aktiviert",
|
||||
"Enter a user message here": "Gebe hier eine Benutzernachricht ein",
|
||||
"Enter an assistant message here": "Gebe hier eine Assistentennachricht ein",
|
||||
"Enter OpenAI API Key": "OpenAI-API-Key eingeben",
|
||||
"Enter stop sequence": "Stop-Sequenz eingeben",
|
||||
"Enter Your Email": "Geben Deine E-Mail-Adresse ein",
|
||||
"Enter Your Full Name": "Gebe Deinen vollständigen Namen ein",
|
||||
"Enter Your Password": "Gebe Dein Passwort ein",
|
||||
"Experimental": "Experimentell",
|
||||
"Export All Chats (All Users)": "Alle Chats exportieren (alle Benutzer)",
|
||||
"Export Chats": "Chats exportieren",
|
||||
"Export Documents Mapping": "Dokumentenmapping exportieren",
|
||||
"Export Modelfiles": "Modelfiles exportieren",
|
||||
"Export Prompts": "Prompts exportieren",
|
||||
"Failed to read clipboard contents": "Fehler beim Lesen des Zwischenablageninhalts",
|
||||
"File Mode": "Dateimodus",
|
||||
"File not found.": "Datei nicht gefunden.",
|
||||
"Focus chat input": "Chat-Eingabe fokussieren",
|
||||
"Format your variables using square brackets like this:": "Formatiere Deine Variablen mit eckigen Klammern wie folgt:",
|
||||
|
@ -187,7 +181,6 @@
|
|||
"Model Tag Name": "Modell-Tag-Name",
|
||||
"Modelfile": "Modelfiles",
|
||||
"Modelfile Advanced Settings": "Erweiterte Modelfileseinstellungen",
|
||||
"Modelfile Content": "Modelfilesinhalt",
|
||||
"Modelfiles": "Modelfiles",
|
||||
"Models": "Modelle",
|
||||
"My Documents": "Meine Dokumente",
|
||||
|
@ -195,19 +188,20 @@
|
|||
"My Prompts": "Meine Prompts",
|
||||
"Name": "Name",
|
||||
"Name Tag": "Namens-Tag",
|
||||
"Name your Modelfile": "Benenne Dein Modelfile",
|
||||
"Name your modelfile": "",
|
||||
"New Chat": "Neuer Chat",
|
||||
"New Password": "Neues Passwort",
|
||||
"Not sure what to add?": "Nicht sicher, was hinzugefügt werden soll?",
|
||||
"Not sure what to write? Switch to": "Nicht sicher, was Du schreiben sollst? Wechsel zu",
|
||||
"Off": "Aus",
|
||||
"Okay, Let's Go!": "Okay, los geht's!",
|
||||
"Ollama API URL": "Ollama-API-URL",
|
||||
"Ollama Version": "Ollama-Version",
|
||||
"On": "Ein",
|
||||
"Only": "Nur",
|
||||
"Only alphanumeric characters and hyphens are allowed in the command string.": "Nur alphanumerische Zeichen und Bindestriche sind im Befehlsstring erlaubt.",
|
||||
"Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "Hoppla! Warte noch einen Moment! Die Dateien sind noch im der Verarbeitung. Bitte habe etwas Geduld und wir informieren Dich, sobald sie bereit sind.",
|
||||
"Oops! Looks like the URL is invalid. Please double-check and try again.": "",
|
||||
"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
|
||||
"Open": "Öffne",
|
||||
"Open AI": "Open AI",
|
||||
"Open new chat": "Neuen Chat öffnen",
|
||||
|
@ -215,7 +209,7 @@
|
|||
"or": "oder",
|
||||
"Parameters": "Parameter",
|
||||
"Password": "Passwort",
|
||||
"pending": "ausstehend",
|
||||
"Pending": "",
|
||||
"Permission denied when accessing microphone: {{error}}": "Zugriff auf das Mikrofon verweigert: {{error}}",
|
||||
"Playground": "Playground",
|
||||
"Profile": "Profil",
|
||||
|
@ -277,6 +271,7 @@
|
|||
"STT Settings": "STT-Einstellungen",
|
||||
"Submit": "Senden",
|
||||
"Success": "Erfolg",
|
||||
"Successfully updated": "",
|
||||
"Successfully updated.": "Erfolgreich aktualisiert.",
|
||||
"Sync All": "Alles synchronisieren",
|
||||
"System": "System",
|
||||
|
@ -290,12 +285,12 @@
|
|||
"Theme": "Design",
|
||||
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Dadurch werden Deine wertvollen Unterhaltungen sicher in der Backend-Datenbank gespeichert. Vielen Dank!",
|
||||
"This setting does not sync across browsers or devices.": "Diese Einstellung wird nicht zwischen Browsern oder Geräten synchronisiert.",
|
||||
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "",
|
||||
"Title": "Titel",
|
||||
"Title Auto-Generation": "Automatische Titelgenerierung",
|
||||
"Title Generation Prompt": "Prompt für Titelgenerierung",
|
||||
"to": "für",
|
||||
"To access the available model names for downloading,": "Um auf die verfügbaren Modellnamen zum Herunterladen zuzugreifen,",
|
||||
"to chat input.": "im Chat eingeben.",
|
||||
"Toggle settings": "Einstellungen umschalten",
|
||||
"Toggle sidebar": "Seitenleiste umschalten",
|
||||
"Top K": "Top K",
|
||||
|
@ -303,12 +298,10 @@
|
|||
"Trouble accessing Ollama?": "Probleme beim Zugriff auf Ollama?",
|
||||
"TTS Settings": "TTS-Einstellungen",
|
||||
"Uh-oh! There was an issue connecting to {{provider}}.": "Ups! Es gab ein Problem bei der Verbindung mit {{provider}}.",
|
||||
"Upload a GGUF model": "Ein GGUF-Modell hochladen",
|
||||
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "",
|
||||
"Upload files": "Dateien hochladen",
|
||||
"Upload Progress": "Upload-Fortschritt",
|
||||
"URL Mode": "URL-Modus",
|
||||
"Use '#' in the prompt input to load and select your documents.": "Verwende '#' in der Prompt-Eingabe, um Deine Dokumente zu laden und auszuwählen.",
|
||||
"user": "Benutzer",
|
||||
"User": "",
|
||||
"User Permissions": "Benutzerberechtigungen",
|
||||
"Users": "Benutzer",
|
||||
"Utilize": "Nutze die",
|
||||
|
@ -322,8 +315,9 @@
|
|||
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Wenn die Historie ausgeschaltet ist, werden neue Chats nicht in Deiner Historie auf Deine Geräte angezeigt.",
|
||||
"Whisper (Local)": "Whisper (Lokal)",
|
||||
"Write a prompt suggestion (e.g. Who are you?)": "Gebe einen Prompt-Vorschlag ein (z.B. Wer bist du?)",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword]": "Schreibe eine kurze Zusammenfassung in 50 Wörtern, die [Thema oder Schlüsselwort] zusammenfasst.",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword].": "Schreibe eine kurze Zusammenfassung in 50 Wörtern, die [Thema oder Schlüsselwort] zusammenfasst.",
|
||||
"You": "Du",
|
||||
"You can help us translate the WebUI.": "Du kannst uns bei der Übersetzung der WebUI helfen.",
|
||||
"You're a helpful assistant.": "Du bist ein hilfreicher Assistent."
|
||||
"You're a helpful assistant.": "Du bist ein hilfreicher Assistent.",
|
||||
"You're now logged in.": "Du bist nun eingeloggt.",
|
||||
"You can help us translate the WebUI.": "Du kannst uns bei der Übersetzung der WebUI helfen."
|
||||
}
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
"Add message": "Add message",
|
||||
"add tags": "add tags",
|
||||
"Adjusting these settings will apply changes universally to all users.": "Adjusting these settings will apply changes universally to all users.",
|
||||
"admin": "Admin",
|
||||
"Admin": "",
|
||||
"Admin Panel": "Admin Panel",
|
||||
"Admin Settings": "Admin Settings",
|
||||
"Advanced": "Advanced",
|
||||
"Advanced Model Params": "Advanced Model Params",
|
||||
"Advanced Parameters": "Advanced Parameters",
|
||||
"all": "all",
|
||||
|
@ -35,7 +34,6 @@
|
|||
"API Key": "API Key",
|
||||
"API RPM": "API RPM",
|
||||
"are allowed - Activate this command by typing": "are allowed - Activate this command by typing",
|
||||
"assistant": "Assistant",
|
||||
"Audio": "Audio",
|
||||
"Auto-playback response": "Auto-playback response",
|
||||
"Auto-send input after 3 sec.": "Auto-send input after 3 sec.",
|
||||
|
@ -121,21 +119,17 @@
|
|||
"Enable Chat History": "Enable Chat History",
|
||||
"Enable New Sign Ups": "Enable New Sign Ups",
|
||||
"Enabled": "Enabled",
|
||||
"Enter a user message here": "Enter a user message here",
|
||||
"Enter an assistant message here": "Enter an assistant message here",
|
||||
"Enter OpenAI API Key": "Enter OpenAI API Key",
|
||||
"Enter stop sequence": "Enter stop sequence",
|
||||
"Enter Your Email": "Enter Your Email",
|
||||
"Enter Your Full Name": "Enter Your Full Name",
|
||||
"Enter Your Password": "Enter Your Password",
|
||||
"Experimental": "Experimental",
|
||||
"Export All Chats (All Users)": "Export All Chats (All Users)",
|
||||
"Export Chats": "Export Chats",
|
||||
"Export Documents Mapping": "Export Documents Mapping",
|
||||
"Export Modelfiles": "Export Modelfiles",
|
||||
"Export Prompts": "Export Prompts",
|
||||
"Failed to read clipboard contents": "Failed to read clipboard contents",
|
||||
"File Mode": "File Mode",
|
||||
"File not found.": "File not found.",
|
||||
"Focus chat input": "Focus chat input",
|
||||
"Format your variables using square brackets like this:": "Format your variables using square brackets like this:",
|
||||
|
@ -187,7 +181,6 @@
|
|||
"Model Tag Name": "Model Tag Name",
|
||||
"Modelfile": "Modelfile",
|
||||
"Modelfile Advanced Settings": "Modelfile Advanced Settings",
|
||||
"Modelfile Content": "Modelfile Content",
|
||||
"Modelfiles": "Modelfiles",
|
||||
"Models": "Models",
|
||||
"My Documents": "My Documents",
|
||||
|
@ -195,19 +188,20 @@
|
|||
"My Prompts": "My Prompts",
|
||||
"Name": "Name",
|
||||
"Name Tag": "Name Tag",
|
||||
"Name your Modelfile": "Name your Modelfile",
|
||||
"Name your modelfile": "",
|
||||
"New Chat": "New Chat",
|
||||
"New Password": "New Password",
|
||||
"Not sure what to add?": "Not sure what to add?",
|
||||
"Not sure what to write? Switch to": "Not sure what to write? Switch to",
|
||||
"Off": "Off",
|
||||
"Okay, Let's Go!": "Okay, Let's Go!",
|
||||
"Ollama API URL": "Ollama API URL",
|
||||
"Ollama Version": "Ollama Version",
|
||||
"On": "On",
|
||||
"Only": "Only",
|
||||
"Only alphanumeric characters and hyphens are allowed in the command string.": "Only alphanumeric characters and hyphens are allowed in the command string.",
|
||||
"Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.",
|
||||
"Oops! Looks like the URL is invalid. Please double-check and try again.": "",
|
||||
"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
|
||||
"Open": "Open",
|
||||
"Open AI": "Open AI",
|
||||
"Open new chat": "Open new chat",
|
||||
|
@ -215,7 +209,7 @@
|
|||
"or": "or",
|
||||
"Parameters": "Parameters",
|
||||
"Password": "Password",
|
||||
"pending": "Pending",
|
||||
"Pending": "",
|
||||
"Permission denied when accessing microphone: {{error}}": "Permission denied when accessing microphone: {{error}}",
|
||||
"Playground": "Playground",
|
||||
"Profile": "Profile",
|
||||
|
@ -277,6 +271,7 @@
|
|||
"STT Settings": "STT Settings",
|
||||
"Submit": "Submit",
|
||||
"Success": "Success",
|
||||
"Successfully updated": "",
|
||||
"Successfully updated.": "Successfully updated.",
|
||||
"Sync All": "Sync All",
|
||||
"System": "System",
|
||||
|
@ -290,12 +285,12 @@
|
|||
"Theme": "Theme",
|
||||
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "This ensures that your valuable conversations are securely saved to your backend database. Thank you!",
|
||||
"This setting does not sync across browsers or devices.": "This setting does not sync across browsers or devices.",
|
||||
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "",
|
||||
"Title": "Title",
|
||||
"Title Auto-Generation": "Title Auto-Generation",
|
||||
"Title Generation Prompt": "Title Generation Prompt",
|
||||
"to": "to",
|
||||
"To access the available model names for downloading,": "To access the available model names for downloading,",
|
||||
"to chat input.": "to chat input.",
|
||||
"Toggle settings": "Toggle settings",
|
||||
"Toggle sidebar": "Toggle sidebar",
|
||||
"Top K": "Top K",
|
||||
|
@ -303,12 +298,10 @@
|
|||
"Trouble accessing Ollama?": "Trouble accessing Ollama?",
|
||||
"TTS Settings": "TTS Settings",
|
||||
"Uh-oh! There was an issue connecting to {{provider}}.": "Uh-oh! There was an issue connecting to {{provider}}.",
|
||||
"Upload a GGUF model": "Upload a GGUF model",
|
||||
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "",
|
||||
"Upload files": "Upload files",
|
||||
"Upload Progress": "Upload Progress",
|
||||
"URL Mode": "URL Mode",
|
||||
"Use '#' in the prompt input to load and select your documents.": "Use '#' in the prompt input to load and select your documents.",
|
||||
"user": "User",
|
||||
"User": "",
|
||||
"User Permissions": "User Permissions",
|
||||
"Users": "Users",
|
||||
"Utilize": "Utilize",
|
||||
|
@ -322,8 +315,9 @@
|
|||
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "When history is turned off, new chats on this browser won't appear in your history on any of your devices.",
|
||||
"Whisper (Local)": "Whisper (Local)",
|
||||
"Write a prompt suggestion (e.g. Who are you?)": "Write a prompt suggestion (e.g. Who are you?)",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword]": "Write a summary in 50 words that summarizes [topic or keyword]",
|
||||
"You can help us translate the WebUI.": "You can help us translate the WebUI.",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword].": "Write a summary in 50 words that summarizes [topic or keyword].",
|
||||
"You": "You",
|
||||
"You're a helpful assistant.": "You're a helpful assistant.",
|
||||
"You're now logged in.": "You're now logged in."
|
||||
"You're now logged in.": "You're now logged in.",
|
||||
"You can help us translate the WebUI.": "You can help us translate the WebUI."
|
||||
}
|
||||
|
|
|
@ -1,42 +1,65 @@
|
|||
{
|
||||
"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' یا '-1' برای غیر فعال کردن انقضا.",
|
||||
"(Beta)": "(بتا)",
|
||||
"(e.g. `sh webui.sh --api`)": "(e.g. `sh webui.sh --api`)",
|
||||
"{{item}} not provided": "{{item}} ارائه نشده است",
|
||||
"{{modelName}} is thinking...": "{{modelName}} در حال فکر کردن است...",
|
||||
"{{webUIName}} Backend Required": "بکند {{webUIName}} نیاز است.",
|
||||
"About": "درباره",
|
||||
"Account": "حساب کاربری",
|
||||
"Action": "عمل",
|
||||
"Add a model": "اضافه کردن یک مدل",
|
||||
"Add a model tag name": "اضافه کردن یک نام تگ برای مدل",
|
||||
"Add a short description about what this modelfile does": "توضیح کوتاهی در مورد کاری که این فایل\u200cمدل انجام می دهد اضافه کنید",
|
||||
"Add a short title for this prompt": "یک عنوان کوتاه برای این درخواست اضافه کنید",
|
||||
"Add Docs": "اضافه کردن اسناد",
|
||||
"Add Files": "اضافه کردن فایلها",
|
||||
"Add Files": "اضافه کردن فایل\u200cها",
|
||||
"Add LiteLLM Model": "اضافه کردن مدل LiteLLM",
|
||||
"add tags": "اضافه کردن تگها",
|
||||
"admin": "مدیریت",
|
||||
"Add message": "اضافه کردن پیغام",
|
||||
"add tags": "اضافه کردن تگ\u200cها",
|
||||
"Adjusting these settings will apply changes universally to all users.": "با تنظیم این تنظیمات، تغییرات به طور کلی برای همه کاربران اعمال می شود.",
|
||||
"Admin": "",
|
||||
"Admin Panel": "پنل مدیریت",
|
||||
"Admin Settings": "تنظیمات مدیریت",
|
||||
"Advanced Model Params": "پارامترهای پیشرفته مدل",
|
||||
"Advanced Parameters": "پارامترهای پیشرفته",
|
||||
"all": "همه",
|
||||
"All Users": "همه کاربران",
|
||||
"Allow": "اجازه دادن",
|
||||
"Allow Chat Deletion": "اجازه حذف گپ",
|
||||
"alphanumeric characters and hyphens": "حروف الفبایی و خط فاصله",
|
||||
"Already have an account?": "از قبل حساب کاربری دارید؟",
|
||||
"and": "و",
|
||||
"API Base URL": "API Base URL",
|
||||
"API Key": "API Key",
|
||||
"API RPM": "API RPM",
|
||||
"are allowed - Activate this command by typing": "مجاز هستند - این دستور را با تایپ کردن این فعال کنید:",
|
||||
"Audio": "صدا",
|
||||
"AUTOMATIC1111 Base URL": "پایه URL AUTOMATIC1111 ",
|
||||
"Auto-playback response": "پخش خودکار پاسخ ",
|
||||
"Auto-send input after 3 sec.": "به طور خودکار ورودی را پس از 3 ثانیه ارسال کن.",
|
||||
"AUTOMATIC1111 Base URL": "پایه URL AUTOMATIC1111 ",
|
||||
"available!": "در دسترس!",
|
||||
"Back": "بازگشت",
|
||||
"Builder Mode": "حالت سازنده",
|
||||
"Cancel": "لغو",
|
||||
"Categories": "دستهبندیها",
|
||||
"Categories": "دسته\u200cبندی\u200cها",
|
||||
"Change Password": "تغییر رمز عبور",
|
||||
"Chat History": "تاریخچهی گفتگو",
|
||||
"Chat": "گپ",
|
||||
"Chat History": "تاریخچه\u200cی گفتگو",
|
||||
"Chat History is off for this browser.": "سابقه گپ برای این مرورگر خاموش است.",
|
||||
"Chats": "گپها",
|
||||
"Chats": "گپ\u200cها",
|
||||
"Check Again": "چک مجدد",
|
||||
"Check for updates": "بررسی به\u200cروزرسانی",
|
||||
"Checking for updates...": "در حال بررسی برای به\u200cروزرسانی..",
|
||||
"Choose a model before saving...": "قبل از ذخیره یک مدل را انتخاب کنید...",
|
||||
"Chunk Overlap": "همپوشانی تکه",
|
||||
"Chunk Params": "پارامترهای تکه",
|
||||
"Chunk Size": "اندازه تکه",
|
||||
"Click here for help": "برای کمک اینجا را کلیک کنید",
|
||||
"Click here to check other modelfiles.": "برای بررسی سایر فایل\u200cهای مدل اینجا را کلیک کنید.",
|
||||
"click here.": "اینجا کلیک کنید.",
|
||||
"Click here to check other modelfiles.": "برای بررسی سایر فایلهای مدل اینجا را کلیک کنید.",
|
||||
"Click on the user role button to change a user's role.": "برای تغییر نقش کاربر، روی دکمه نقش کاربر کلیک کنید.",
|
||||
"Close": "بسته",
|
||||
"Collection": "مجموعه",
|
||||
"Command": "دستور",
|
||||
"Confirm Password": "تایید رمز عبور",
|
||||
|
@ -44,68 +67,86 @@
|
|||
"Content": "محتوا",
|
||||
"Context Length": "طول زمینه",
|
||||
"Conversation Mode": "حالت مکالمه",
|
||||
"Copying to clipboard was successful!": "کپی کردن در کلیپ بورد با موفقیت انجام شد!",
|
||||
"Copy last code block": "کپی آخرین بلوک کد",
|
||||
"Copy last response": "کپی آخرین پاسخ",
|
||||
"Copying to clipboard was successful!": "کپی کردن در کلیپ بورد با موفقیت انجام شد!",
|
||||
"Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "یک عبارت مختصر و ۳ تا ۵ کلمه ای را به عنوان سرفصل برای پرس و جو زیر ایجاد کنید، به شدت محدودیت ۳-۵ کلمه را رعایت کنید و از استفاده از کلمه 'عنوان' خودداری کنید:",
|
||||
"Create a modelfile": "ایجاد یک فایل مدل",
|
||||
"Create Account": "ساخت حساب کاربری",
|
||||
"Created at": "ایجاد شده در",
|
||||
"Created by": "ایجاد شده توسط",
|
||||
"Current Model": "مدل فعلی",
|
||||
"Current Password": "رمز عبور فعلی",
|
||||
"Custom": "دلخواه",
|
||||
"Customize Ollama models for a specific purpose": "مدل های اولاما را برای یک هدف خاص سفارشی کنید",
|
||||
"Dark": "تیره",
|
||||
"Database": "پایگاه داده",
|
||||
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
|
||||
"Default": "پیشفرض",
|
||||
"Default model updated": "مدل پیشفرض بهروزرسانی شد",
|
||||
"Default (Web API)": "پیشفرض (Web API)",
|
||||
"Default model updated": "مدل پیشفرض به\u200cروزرسانی شد",
|
||||
"Default Prompt Suggestions": "پیشنهادات پرامپت پیش فرض",
|
||||
"Default User Role": "نقش کاربر پیش فرض",
|
||||
"Default (Web API)": "پیشفرض (Web API)",
|
||||
"delete": "حذف",
|
||||
"Delete a model": "حذف یک مدل",
|
||||
"Delete chat": "حذف گپ",
|
||||
"Delete Chats": "حذف گپها",
|
||||
"Delete Chats": "حذف گپ\u200cها",
|
||||
"Deleted {{deleteModelTag}}": "{{deleteModelTag}} پاک شد",
|
||||
"delete": "حذف",
|
||||
"Deleted {tagName}": "{tagName} حذف شد",
|
||||
"Description": "توضیحات",
|
||||
"Desktop Notifications": "اعلان",
|
||||
"Disabled": "غیرفعال",
|
||||
"Discover a modelfile": "فایل مدل را کشف کنید",
|
||||
"Discover a prompt": "یک اعلان را کشف کنید",
|
||||
"Discover, download, and explore custom prompts": "پرامپتهای سفارشی را کشف، دانلود و کاوش کنید",
|
||||
"Discover, download, and explore custom prompts": "پرامپت\u200cهای سفارشی را کشف، دانلود و کاوش کنید",
|
||||
"Discover, download, and explore model presets": "پیش تنظیمات مدل را کشف، دانلود و کاوش کنید",
|
||||
"Display the username instead of You in the Chat": "نمایش نام کاربری به جای «شما» در چت",
|
||||
"Document": "سند",
|
||||
"Documents": "اسناد",
|
||||
"Document Settings": "تنظیمات سند",
|
||||
"Documents": "اسناد",
|
||||
"does not make any external connections, and your data stays securely on your locally hosted server.": "هیچ اتصال خارجی ایجاد نمی کند و داده های شما به طور ایمن در سرور میزبان محلی شما باقی می ماند.",
|
||||
"Don't Allow": "اجازه نده",
|
||||
"Don't have an account?": "حساب کاربری ندارید؟",
|
||||
"Download as a File": "دانلود به صورت فایل",
|
||||
"Download Database": "دانلود پایگاه داده",
|
||||
"Drop any files here to add to the conversation": "هر فایلی را اینجا رها کنید تا به مکالمه اضافه شود",
|
||||
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "به طور مثال '30s','10m'. واحد\u200cهای زمانی معتبر 's', 'm', 'h' هستند.",
|
||||
"Edit Doc": "ویرایش سند",
|
||||
"Edit User": "ویرایش کاربر",
|
||||
"Email": "ایمیل",
|
||||
"Enable Chat History": "تاریخچه چت را فعال کنید",
|
||||
"Enable New Sign Ups": "فعال کردن ثبت نام\u200cهای جدید",
|
||||
"Enabled": "فعال",
|
||||
"Enable New Sign Ups": "فعال کردن ثبت نامهای جدید",
|
||||
"Experimental": "آزمایشی",
|
||||
"Export All Chats (All Users)": "اکسپورت از همه گپها(همه کاربران)",
|
||||
"Export Chats": "اکسپورت از گپها",
|
||||
"Enter OpenAI API Key": "کلید OpenAI API را وارد کنید",
|
||||
"Enter stop sequence": "توالی توقف را وارد کنید",
|
||||
"Enter Your Email": "ایمیل خود را وارد کنید",
|
||||
"Enter Your Full Name": "نام کامل خود را وارد کنید",
|
||||
"Enter Your Password": "رمز عبور خود را وارد کنید",
|
||||
"Export All Chats (All Users)": "اکسپورت از همه گپ\u200cها(همه کاربران)",
|
||||
"Export Chats": "اکسپورت از گپ\u200cها",
|
||||
"Export Documents Mapping": "اکسپورت از نگاشت اسناد",
|
||||
"Export Modelfiles": "اکسپورت از فایلهای مدل",
|
||||
"Export Prompts": "اکسپورت از پرامپتها",
|
||||
"Export Modelfiles": "اکسپورت از فایل\u200cهای مدل",
|
||||
"Export Prompts": "اکسپورت از پرامپت\u200cها",
|
||||
"Failed to read clipboard contents": "خواندن محتوای کلیپ بورد ناموفق بود",
|
||||
"File Mode": "حالت فایل",
|
||||
"File not found.": "فایل یافت نشد.",
|
||||
"Focus chat input": "فوکوس کردن ورودی گپ",
|
||||
"Format your variables using square brackets like this:": "متغیرهای خود را با استفاده از براکت مربع به شکل زیر قالب بندی کنید:",
|
||||
"From (Base Model)": "از (مدل پایه)",
|
||||
"Full Screen Mode": "حالت تمام صفحه",
|
||||
"General": "عمومی",
|
||||
"General Settings": "تنظیمات عمومی",
|
||||
"Hello, {{name}}": "سلام، {{name}}",
|
||||
"Hide": "پنهان",
|
||||
"How can I help you today?": "امروز چطور می توانم کمک تان کنم؟",
|
||||
"Image Generation (Experimental)": "تولید تصویر (آزمایشی)",
|
||||
"Image Settings": "تنظیمات تصویر",
|
||||
"Images": "تصاویر",
|
||||
"Import Chats": "ایمپورت گپها",
|
||||
"Import Chats": "ایمپورت گپ\u200cها",
|
||||
"Import Documents Mapping": "ایمپورت نگاشت اسناد",
|
||||
"Import Modelfiles": "ایمپورت فایلهای مدل",
|
||||
"Import Prompts": "ایمپورت پرامپتها",
|
||||
"Import Modelfiles": "ایمپورت فایل\u200cهای مدل",
|
||||
"Import Prompts": "ایمپورت پرامپت\u200cها",
|
||||
"Include `--api` flag when running stable-diffusion-webui": "فلگ `--api` را هنکام اجرای stable-diffusion-webui استفاده کنید.",
|
||||
"Interface": "رابط",
|
||||
"{{item}} not provided": "{{item}} ارائه نشده است",
|
||||
"join our Discord for help.": "برای کمک به دیسکورد ما بپیوندید.",
|
||||
"JSON": "JSON",
|
||||
"JWT Expiration": "JWT انقضای",
|
||||
|
@ -118,80 +159,90 @@
|
|||
"LiteLLM API Base URL": "LiteLLM API Base URL",
|
||||
"LiteLLM API Key": "LiteLLM API Key",
|
||||
"LiteLLM API RPM": "LiteLLM API RPM",
|
||||
"LLMs can make mistakes. Verify important information.": "مدلهای زبانی بزرگ میتوانند اشتباه کنند. اطلاعات مهم را راستیآزمایی کنید.",
|
||||
"LLMs can make mistakes. Verify important information.": "مدل\u200cهای زبانی بزرگ می\u200cتوانند اشتباه کنند. اطلاعات مهم را راستی\u200cآزمایی کنید.",
|
||||
"Made by OpenWebUI Community": "ساخته شده توسط OpenWebUI Community",
|
||||
"Make sure to enclose them with": "مطمئن شوید که آنها را با این محصور کنید:",
|
||||
"Manage LiteLLM Models": "Manage LiteLLM Models",
|
||||
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "حداکثر 3 مدل را می توان به طور همزمان دانلود کرد. لطفاً بعداً دوباره امتحان کنید.",
|
||||
"Manage Ollama Models": "مدیریت مدل\u200cهای اولاما",
|
||||
"Max Tokens": "حداکثر توکن",
|
||||
"Mirostat Eta": "Mirostat Eta",
|
||||
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "حداکثر 3 مدل را می توان به طور همزمان دانلود کرد. لطفاً بعداً دوباره امتحان کنید.",
|
||||
"Mirostat": "Mirostat",
|
||||
"Mirostat Eta": "Mirostat Eta",
|
||||
"Mirostat Tau": "Mirostat Tau",
|
||||
"MMMM DD, YYYY": "MMMM DD, YYYY",
|
||||
"Model '{{modelName}}' has been successfully downloaded.": "مدل '{{modelName}}' با موفقیت دانلود شد.",
|
||||
"Modelfile Advanced Settings": "تنظیمات پیشرفته فایلمدل",
|
||||
"Modelfile Content": "محتویات فایلمدل",
|
||||
"Modelfile": "فایل مدل",
|
||||
"Modelfiles": "فایلهای مدل",
|
||||
"Model '{{modelTag}}' is already in queue for downloading.": "مدل '{{modelTag}}' در حال حاضر در صف برای دانلود است.",
|
||||
"Model {{modelId}} not found": "مدل {{modelId}} یافت نشد",
|
||||
"Model {{modelName}} already exists.": "مدل {{modelName}} در حال حاضر وجود دارد.",
|
||||
"Model '{{modelTag}}' is already in queue for downloading.": "مدل '{{modelTag}}' در حال حاضر در صف برای دانلود است.",
|
||||
"{{modelName}} is thinking...": "{{modelName}} در حال فکر کردن است...",
|
||||
"Model Name": "نام مدل",
|
||||
"Model not selected": "مدل انتخاب نشده",
|
||||
"Models": "مدلها",
|
||||
"Model Tag Name": "نام تگ مدل",
|
||||
"Modelfile": "فایل مدل",
|
||||
"Modelfile Advanced Settings": "تنظیمات پیشرفته فایل\u200cمدل",
|
||||
"Modelfiles": "فایل\u200cهای مدل",
|
||||
"Models": "مدل\u200cها",
|
||||
"My Documents": "اسناد من",
|
||||
"My Modelfiles": "فایلهای مدل من",
|
||||
"My Prompts": "پرامپتهای من",
|
||||
"My Modelfiles": "فایل\u200cهای مدل من",
|
||||
"My Prompts": "پرامپت\u200cهای من",
|
||||
"Name": "نام",
|
||||
"Name Tag": "نام تگ",
|
||||
"Name your modelfile": "",
|
||||
"New Chat": "گپ جدید",
|
||||
"New Password": "رمز عبور جدید",
|
||||
"Desktop Notifications": "اعلان",
|
||||
"Not sure what to add?": "مطمئن نیستید چه چیزی را اضافه کنید؟",
|
||||
"Not sure what to write? Switch to": "مطمئن نیستید چه بنویسید؟ تغییر به",
|
||||
"Off": "خاموش",
|
||||
"Okay, Let's Go!": "باشه، بزن بریم!",
|
||||
"Ollama API URL": "اولاما API URL",
|
||||
"Ollama Version": "نسخه Ollama",
|
||||
"Only alphanumeric characters and hyphens are allowed in the command string.": "فقط کاراکترهای الفبایی و خط فاصله در رشته فرمان مجاز هستند.",
|
||||
"On": "روشن",
|
||||
"Only": "فقط",
|
||||
"Only alphanumeric characters and hyphens are allowed in the command string.": "فقط کاراکترهای الفبایی و خط فاصله در رشته فرمان مجاز هستند.",
|
||||
"Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "اوه! فایل های شما هنوز در فر پردازش هستند. ما آنها را کامل می پزیم. لطفا صبور باشید، به محض آماده شدن به شما اطلاع خواهیم داد.",
|
||||
"OpenAI API": "OpenAI API",
|
||||
"Oops! Looks like the URL is invalid. Please double-check and try again.": "",
|
||||
"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
|
||||
"Open": "باز",
|
||||
"Open AI": "Open AI",
|
||||
"Open new chat": "باز کردن گپ جدید",
|
||||
"OpenAI API": "OpenAI API",
|
||||
"or": "روشن",
|
||||
"Parameters": "پارامترها",
|
||||
"Password": "رمز عبور",
|
||||
"pending": "Pending",
|
||||
"Pending": "",
|
||||
"Permission denied when accessing microphone: {{error}}": "هنگام دسترسی به میکروفون، اجازه داده نشد: {{error}}",
|
||||
"Playground": "زمین بازی",
|
||||
"Profile": "پروفایل",
|
||||
"Prompt Content": "محتویات پرامپت",
|
||||
"Prompts": "پرامپتها",
|
||||
"Prompt suggestions": "پیشنهادات پرامپت",
|
||||
"Prompts": "پرامپت\u200cها",
|
||||
"Pull a model from Ollama.com": "دریافت یک مدل از Ollama.com",
|
||||
"Pull Progress": "پیشرفت دریافت",
|
||||
"RAG Template": "RAG الگوی",
|
||||
"Raw Format": "فرمت خام",
|
||||
"Record voice": "ضبط صدا",
|
||||
"Redirecting you to OpenWebUI Community": "در حال هدایت به OpenWebUI Community",
|
||||
"Release Notes": "یادداشتهای انتشار",
|
||||
"Release Notes": "یادداشت\u200cهای انتشار",
|
||||
"Repeat Last N": "Repeat Last N",
|
||||
"Repeat Penalty": "Repeat Penalty",
|
||||
"Request Mode": "حالت درخواست",
|
||||
"Reset Vector Storage": "بازنشانی ذخیره سازی برداری",
|
||||
"Response AutoCopy to Clipboard": "کپی خودکار پاسخ به کلیپ بورد",
|
||||
"Role": "نقش",
|
||||
"Ros\u00e9 Pine Dawn": "Ros\u00e9 Pine Dawn",
|
||||
"Ros\u00e9 Pine": "Ros\u00e9 Pine",
|
||||
"Save & Create": "ذخیره و ایجاد",
|
||||
"Rosé Pine": "Rosé Pine",
|
||||
"Rosé Pine Dawn": "Rosé Pine Dawn",
|
||||
"Save": "ذخیره",
|
||||
"Save & Create": "ذخیره و ایجاد",
|
||||
"Save & Submit": "ذخیره و ارسال",
|
||||
"Save & Update": "ذخیره و بهروزرسانی",
|
||||
"Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "ذخیره گزارشهای چت مستقیماً در حافظه مرورگر شما دیگر پشتیبانی نمیشود. لطفاً با کلیک بر روی دکمه زیر، چند لحظه برای دانلود و حذف گزارش های چت خود وقت بگذارید. نگران نباشید، شما به راحتی می توانید گزارش های چت خود را از طریق بکند دوباره وارد کنید",
|
||||
"Save & Update": "ذخیره و به\u200cروزرسانی",
|
||||
"Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "ذخیره گزارش\u200cهای چت مستقیماً در حافظه مرورگر شما دیگر پشتیبانی نمی\u200cشود. لطفاً با کلیک بر روی دکمه زیر، چند لحظه برای دانلود و حذف گزارش های چت خود وقت بگذارید. نگران نباشید، شما به راحتی می توانید گزارش های چت خود را از طریق بکند دوباره وارد کنید",
|
||||
"Scan": "اسکن",
|
||||
"Scan complete!": "اسکن کامل شد!",
|
||||
"Scan for documents from {{path}}": "اسکن اسناد از {{path}}",
|
||||
"Scan": "اسکن",
|
||||
"Search": "جستجو",
|
||||
"Search Documents": "جستجوی اسناد",
|
||||
"Search Prompts": "جستجوی پرامپت\u200cها",
|
||||
"See readme.md for instructions": "برای مشاهده دستورالعمل\u200cها به readme.md مراجعه کنید",
|
||||
"See what's new": "ببینید موارد جدید چه بوده",
|
||||
"Seed": "Seed",
|
||||
"See readme.md for instructions": "برای مشاهده دستورالعملها به readme.md مراجعه کنید",
|
||||
"Select a model": "انتخاب یک مدل",
|
||||
"Send a Messsage": "ارسال یک پیام",
|
||||
"Send message": "ارسال پیام",
|
||||
|
@ -199,129 +250,71 @@
|
|||
"Set as default": "تنظیم به عنوان پیشفرض",
|
||||
"Set Default Model": "تنظیم مدل پیش فرض",
|
||||
"Set Image Size": "تنظیم اندازه تصویر",
|
||||
"Set Steps": "تنظیم گامها",
|
||||
"Settings": "تنظیمات",
|
||||
"Set Steps": "تنظیم گام\u200cها",
|
||||
"Set Title Auto-Generation Model": "تنظیم مدل تولید خودکار عنوان",
|
||||
"Set Voice": "تنظیم صدا",
|
||||
"Settings": "تنظیمات",
|
||||
"Share to OpenWebUI Community": "اشتراک گذاری با OpenWebUI Community",
|
||||
"short-summary": "خلاصه کوتاه",
|
||||
"Show": "نمایش",
|
||||
"Show shortcuts": "نمایش میانبرها",
|
||||
"sidebar": "نوار کناری",
|
||||
"Sign in": "ورود",
|
||||
"Sign Out": "خروج",
|
||||
"SpeechRecognition API is not supported in this browser.": "API تشخیص گفتار در این مرورگر پشتیبانی نمی شود.",
|
||||
"Sign up": "ثبت نام",
|
||||
"Speech recognition error: {{error}}": "خطای تشخیص گفتار: {{error}}",
|
||||
"Speech-to-Text Engine": "موتور گفتار به متن",
|
||||
"SpeechRecognition API is not supported in this browser.": "API تشخیص گفتار در این مرورگر پشتیبانی نمی شود.",
|
||||
"Stop Sequence": "توالی توقف",
|
||||
"STT Settings": "STT تنظیمات",
|
||||
"Successfully updated.": "با موفقیت به روز شد",
|
||||
"Submit": "ارسال",
|
||||
"Success": "موفقیت",
|
||||
"Successfully updated": "",
|
||||
"Successfully updated.": "با موفقیت به روز شد",
|
||||
"Sync All": "همگام سازی همه",
|
||||
"System": "سیستم",
|
||||
"System Prompt": "پرامپت سیستم",
|
||||
"Tags": "تگها",
|
||||
"Tags": "تگ\u200cها",
|
||||
"Temperature": "دما",
|
||||
"Template": "الگو",
|
||||
"Text Completion": "تکمیل متن",
|
||||
"Text-to-Speech Engine": "موتور تبدیل متن به گفتار",
|
||||
"Tfs Z": "Tfs Z",
|
||||
"Theme": "قالب",
|
||||
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "این تضمین می کند که مکالمات ارزشمند شما به طور ایمن در پایگاه داده بکند ذخیره می شود. تشکر!",
|
||||
"This setting does not sync across browsers or devices.": "این تنظیم در مرورگرها یا دستگاه\u200cها همگام\u200cسازی نمی\u200cشود.",
|
||||
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "",
|
||||
"Title": "عنوان",
|
||||
"Title Auto-Generation": "تولید خودکار عنوان",
|
||||
"Title Generation Prompt": "پرامپت تولید عنوان",
|
||||
"Title": "عنوان",
|
||||
"to": "به",
|
||||
"To access the available model names for downloading,": "برای دسترسی به نام مدل های موجود برای دانلود،",
|
||||
"Toggle settings": "نمایش/عدم نمایش تنظیمات",
|
||||
"Toggle sidebar": "نمایش/عدم نمایش نوار کناری",
|
||||
"Top K": "Top K",
|
||||
"Top P": "Top P",
|
||||
"Trouble accessing Ollama?": "در دسترسی به اولاما مشکل دارید؟",
|
||||
"TTS Settings": "تنظیمات TTS",
|
||||
"Uh-oh! There was an issue connecting to {{provider}}.": "اوه اوه! مشکلی در اتصال به {{provider}} وجود داشت.",
|
||||
"Upload a GGUF model": "بارگذاری یک مدل GGUF",
|
||||
"Upload files": "بارگذاری فایلها",
|
||||
"Upload Progress": "میزان پیشرفت بارگذاری",
|
||||
"URL Mode": "حالت URL",
|
||||
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "",
|
||||
"Upload files": "بارگذاری فایل\u200cها",
|
||||
"Use '#' in the prompt input to load and select your documents.": "در پرامپت از '#' برای لود و انتخاب اسناد خود استفاده کنید.",
|
||||
"User": "",
|
||||
"User Permissions": "مجوزهای کاربر",
|
||||
"Users": "کاربران",
|
||||
"user": "کاربر",
|
||||
"WebUI Add-ons": "WebUI افزونههای",
|
||||
"{{webUIName}} Backend Required": "بکند {{webUIName}} نیاز است.",
|
||||
"WebUI Settings": "تنظیمات WebUI",
|
||||
"Web": "وب",
|
||||
"Whisper (Local)": "ویسپر (محلی)",
|
||||
"You're now logged in.": "شما اکنون وارد شدهاید.",
|
||||
"Hide": "پنهان",
|
||||
"Show": "نمایش",
|
||||
"Enter stop sequence": "توالی توقف را وارد کنید",
|
||||
"Enter OpenAI API Key": "کلید OpenAI API را وارد کنید",
|
||||
"Current Model": "مدل فعلی",
|
||||
"Display the username instead of You in the Chat": "نمایش نام کاربری به جای «شما» در چت",
|
||||
"Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "یک عبارت مختصر و ۳ تا ۵ کلمه ای را به عنوان سرفصل برای پرس و جو زیر ایجاد کنید، به شدت محدودیت ۳-۵ کلمه را رعایت کنید و از استفاده از کلمه 'عنوان' خودداری کنید:",
|
||||
"Search": "جستجو",
|
||||
"Search Documents": "جستجوی اسناد",
|
||||
"Use '#' in the prompt input to load and select your documents.": "در پرامپت از '#' برای لود و انتخاب اسناد خود استفاده کنید.",
|
||||
"All Users": "همه کاربران",
|
||||
"Click on the user role button to change a user's role.": "برای تغییر نقش کاربر، روی دکمه نقش کاربر کلیک کنید.",
|
||||
"Manage Ollama Models": "مدیریت مدلهای اولاما",
|
||||
"Advanced": "پیشرفته",
|
||||
"Click here for help": "برای کمک اینجا را کلیک کنید",
|
||||
"Not sure what to add?": "مطمئن نیستید چه چیزی را اضافه کنید؟",
|
||||
"Adjusting these settings will apply changes universally to all users.": "با تنظیم این تنظیمات، تغییرات به طور کلی برای همه کاربران اعمال می شود.",
|
||||
"Trouble accessing Ollama?": "در دسترسی به اولاما مشکل دارید؟",
|
||||
"(e.g. `sh webui.sh --api`)": "(e.g. `sh webui.sh --api`)",
|
||||
"Include `--api` flag when running stable-diffusion-webui": "فلگ `--api` را هنکام اجرای stable-diffusion-webui استفاده کنید.",
|
||||
"This setting does not sync across browsers or devices.": "این تنظیم در مرورگرها یا دستگاهها همگامسازی نمیشود.",
|
||||
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "وقتی سابقه خاموش است، چتهای جدید در این مرورگر در سابقه شما در هیچ یک از دستگاههایتان ظاهر نمیشوند.",
|
||||
"Enable Chat History": "تاریخچه چت را فعال کنید",
|
||||
"Search Prompts": "جستجوی پرامپتها",
|
||||
"available!": "در دسترس!",
|
||||
"Created by": "ایجاد شده توسط",
|
||||
"Check for updates": "بررسی بهروزرسانی",
|
||||
"See what's new": "ببینید موارد جدید چه بوده",
|
||||
"Checking for updates...": "در حال بررسی برای بهروزرسانی..",
|
||||
"What’s New in": "موارد جدید در",
|
||||
"Enter Your Email": "ایمیل خود را وارد کنید",
|
||||
"Enter Your Password": "رمز عبور خود را وارد کنید",
|
||||
"Enter Your Full Name": "نام کامل خود را وارد کنید",
|
||||
"Sign in": "ورود",
|
||||
"Sign up": "ثبت نام",
|
||||
"Create Account": "ساخت حساب کاربری",
|
||||
"Don't have an account?": "حساب کاربری ندارید؟",
|
||||
"Already have an account?": "از قبل حساب کاربری دارید؟",
|
||||
"to": "به",
|
||||
"does not make any external connections, and your data stays securely on your locally hosted server.": "هیچ اتصال خارجی ایجاد نمی کند و داده های شما به طور ایمن در سرور میزبان محلی شما باقی می ماند.",
|
||||
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
|
||||
"MMMM DD, YYYY": "MMMM DD, YYYY",
|
||||
"Created at": "ایجاد شده در",
|
||||
"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' یا '-1' برای غیر فعال کردن انقضا.",
|
||||
"Valid time units:": "واحدهای زمانی معتبر:",
|
||||
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "به طور مثال '30s','10m'. واحدهای زمانی معتبر 's', 'm', 'h' هستند.",
|
||||
"Name your Modelfile": "فایلمدل خود را نامگذاری کنید",
|
||||
"Add a model tag name": "اضافه کردن یک نام تگ برای مدل",
|
||||
"Add a short description about what this modelfile does": "توضیح کوتاهی در مورد کاری که این فایلمدل انجام می دهد اضافه کنید",
|
||||
"Write a prompt suggestion (e.g. Who are you?)": "یک پیشنهاد پرامپت بنویسید (مثلاً شما کی هستید؟)",
|
||||
"Only": "فقط",
|
||||
"alphanumeric characters and hyphens": "حروف الفبایی و خط فاصله",
|
||||
"are allowed - Activate this command by typing": "مجاز هستند - این دستور را با تایپ کردن این فعال کنید:",
|
||||
"to chat input.": "در ورودی گپ",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword]": "خلاصه ای در 50 کلمه بنویسید که [موضوع یا کلمه کلیدی] را خلاصه کند.",
|
||||
"variable": "متغیر",
|
||||
"Format your variables using square brackets like this:": "متغیرهای خود را با استفاده از براکت مربع به شکل زیر قالب بندی کنید:",
|
||||
"Make sure to enclose them with": "مطمئن شوید که آنها را با این محصور کنید:",
|
||||
"and": "و",
|
||||
"Utilize": "استفاده کنید",
|
||||
"Valid time units:": "واحدهای زمانی معتبر:",
|
||||
"variable": "متغیر",
|
||||
"variable to have them replaced with clipboard content.": "متغیر برای جایگزینی آنها با محتوای کلیپ بورد.",
|
||||
"short-summary": "خلاصه کوتاه",
|
||||
"Add a short title for this prompt": "یک عنوان کوتاه برای این درخواست اضافه کنید",
|
||||
"Open": "باز",
|
||||
"Close": "بسته",
|
||||
"sidebar": "نوار کناری",
|
||||
"Playground": "زمین بازی",
|
||||
"Submit": "ارسال",
|
||||
"(Beta)": "(بتا)",
|
||||
"Text Completion": "تکمیل متن",
|
||||
"Chat": "گپ",
|
||||
"Web": "وب",
|
||||
"WebUI Add-ons": "WebUI افزونه\u200cهای",
|
||||
"WebUI Settings": "تنظیمات WebUI",
|
||||
"What’s New in": "موارد جدید در",
|
||||
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "وقتی سابقه خاموش است، چت\u200cهای جدید در این مرورگر در سابقه شما در هیچ یک از دستگاه\u200cهایتان ظاهر نمی\u200cشوند.",
|
||||
"Whisper (Local)": "ویسپر (محلی)",
|
||||
"Write a prompt suggestion (e.g. Who are you?)": "یک پیشنهاد پرامپت بنویسید (مثلاً شما کی هستید؟)",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword].": "خلاصه ای در 50 کلمه بنویسید که [موضوع یا کلمه کلیدی] را خلاصه کند.",
|
||||
"You": "شما",
|
||||
"You're a helpful assistant.": "تو یک دستیار سودمند هستی.",
|
||||
"System": "سیستم",
|
||||
"assistant": "دستیار",
|
||||
"Add message": "اضافه کردن پیغام",
|
||||
"Enter a user message here": "در اینجا یک پیام کاربر را وارد کنید",
|
||||
"Enter an assistant message here": "در اینجا یک پیام دستیار را وارد کنید",
|
||||
"Drop any files here to add to the conversation": "هر فایلی را اینجا رها کنید تا به مکالمه اضافه شود",
|
||||
"You": "شما"
|
||||
"You're now logged in.": "شما اکنون وارد شده\u200cاید."
|
||||
}
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
"Add message": "Ajouter un message",
|
||||
"add tags": "ajouter des tags",
|
||||
"Adjusting these settings will apply changes universally to all users.": "L'ajustement de ces paramètres appliquera les changements à tous les utilisateurs.",
|
||||
"admin": "Administrateur",
|
||||
"Admin": "",
|
||||
"Admin Panel": "Panneau d'administration",
|
||||
"Admin Settings": "Paramètres d'administration",
|
||||
"Advanced": "Avancé",
|
||||
"Advanced Model Params": "Paramètres avancés du modèle",
|
||||
"Advanced Parameters": "Paramètres avancés",
|
||||
"all": "tous",
|
||||
|
@ -35,7 +34,6 @@
|
|||
"API Key": "Clé API",
|
||||
"API RPM": "RPM API",
|
||||
"are allowed - Activate this command by typing": "sont autorisés - Activez cette commande en tapant",
|
||||
"assistant": "Assistant",
|
||||
"Audio": "Audio",
|
||||
"Auto-playback response": "Réponse en lecture automatique",
|
||||
"Auto-send input after 3 sec.": "Envoyer automatiquement l'entrée après 3 sec.",
|
||||
|
@ -72,6 +70,7 @@
|
|||
"Copy last code block": "Copier le dernier bloc de code",
|
||||
"Copy last response": "Copier la dernière réponse",
|
||||
"Copying to clipboard was successful!": "La copie dans le presse-papiers a réussi !",
|
||||
"Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "Créez une phrase concise de 3-5 mots comme en-tête pour la requête suivante, en respectant strictement la limite de 3-5 mots et en évitant l'utilisation du mot 'titre' :",
|
||||
"Create a modelfile": "Créer un fichier de modèle",
|
||||
"Create Account": "Créer un compte",
|
||||
"Created at": "Créé le",
|
||||
|
@ -87,7 +86,6 @@
|
|||
"Default (Web API)": "Par défaut (API Web)",
|
||||
"Default model updated": "Modèle par défaut mis à jour",
|
||||
"Default Prompt Suggestions": "Suggestions de prompt par défaut",
|
||||
"Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "Créez une phrase concise de 3-5 mots comme en-tête pour la requête suivante, en respectant strictement la limite de 3-5 mots et en évitant l'utilisation du mot 'titre' :",
|
||||
"Default User Role": "Rôle d'utilisateur par défaut",
|
||||
"delete": "supprimer",
|
||||
"Delete a model": "Supprimer un modèle",
|
||||
|
@ -119,21 +117,17 @@
|
|||
"Enable Chat History": "Activer l'historique du chat",
|
||||
"Enable New Sign Ups": "Activer les nouvelles inscriptions",
|
||||
"Enabled": "Activé",
|
||||
"Enter a user message here": "Entrez un message d'utilisateur ici",
|
||||
"Enter an assistant message here": "Entrez un message d'assistant ici",
|
||||
"Enter OpenAI API Key": "Entrez la clé API OpenAI",
|
||||
"Enter stop sequence": "Entrez la séquence d'arrêt",
|
||||
"Enter Your Email": "Entrez votre email",
|
||||
"Enter Your Full Name": "Entrez votre nom complet",
|
||||
"Enter Your Password": "Entrez votre mot de passe",
|
||||
"Experimental": "Expérimental",
|
||||
"Export All Chats (All Users)": "Exporter tous les chats (tous les utilisateurs)",
|
||||
"Export Chats": "Exporter les chats",
|
||||
"Export Documents Mapping": "Exporter la correspondance des documents",
|
||||
"Export Modelfiles": "Exporter les fichiers de modèle",
|
||||
"Export Prompts": "Exporter les prompts",
|
||||
"Failed to read clipboard contents": "Échec de la lecture du contenu du presse-papiers",
|
||||
"File Mode": "Mode fichier",
|
||||
"File not found.": "Fichier non trouvé.",
|
||||
"Focus chat input": "Concentrer sur l'entrée du chat",
|
||||
"Format your variables using square brackets like this:": "Formatez vos variables en utilisant des crochets comme ceci :",
|
||||
|
@ -185,7 +179,6 @@
|
|||
"Model Tag Name": "Nom de tag du modèle",
|
||||
"Modelfile": "Fichier de modèle",
|
||||
"Modelfile Advanced Settings": "Paramètres avancés du fichier de modèle",
|
||||
"Modelfile Content": "Contenu du fichier de modèle",
|
||||
"Modelfiles": "Fichiers de modèle",
|
||||
"Models": "Modèles",
|
||||
"My Documents": "Mes documents",
|
||||
|
@ -193,19 +186,20 @@
|
|||
"My Prompts": "Mes prompts",
|
||||
"Name": "Nom",
|
||||
"Name Tag": "Tag de nom",
|
||||
"Name your Modelfile": "Nommez votre fichier de modèle",
|
||||
"Name your modelfile": "",
|
||||
"New Chat": "Nouveau chat",
|
||||
"New Password": "Nouveau mot de passe",
|
||||
"Not sure what to add?": "Vous ne savez pas quoi ajouter ?",
|
||||
"Not sure what to write? Switch to": "Vous ne savez pas quoi écrire ? Basculer vers",
|
||||
"Off": "Désactivé",
|
||||
"Okay, Let's Go!": "D'accord, allons-y !",
|
||||
"Ollama API URL": "URL de l'API Ollama",
|
||||
"Ollama Version": "Version Ollama",
|
||||
"On": "Activé",
|
||||
"Only": "Seulement",
|
||||
"Only alphanumeric characters and hyphens are allowed in the command string.": "Seuls les caractères alphanumériques et les tirets sont autorisés dans la chaîne de commande.",
|
||||
"Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "Oups ! Tenez bon ! Vos fichiers sont encore dans le four. Nous les cuisinons à la perfection. Soyez patient et nous vous informerons dès qu'ils seront prêts.",
|
||||
"Oops! Looks like the URL is invalid. Please double-check and try again.": "",
|
||||
"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "",
|
||||
"Open": "Ouvrir",
|
||||
"Open AI": "Open AI",
|
||||
"Open new chat": "Ouvrir un nouveau chat",
|
||||
|
@ -213,7 +207,7 @@
|
|||
"or": "ou",
|
||||
"Parameters": "Paramètres",
|
||||
"Password": "Mot de passe",
|
||||
"pending": "en attente",
|
||||
"Pending": "",
|
||||
"Permission denied when accessing microphone: {{error}}": "Permission refusée lors de l'accès au microphone : {{error}}",
|
||||
"Playground": "Aire de jeu",
|
||||
"Profile": "Profil",
|
||||
|
@ -275,6 +269,7 @@
|
|||
"STT Settings": "Paramètres STT",
|
||||
"Submit": "Soumettre",
|
||||
"Success": "Succès",
|
||||
"Successfully updated": "",
|
||||
"Successfully updated.": "Mis à jour avec succès.",
|
||||
"Sync All": "Synchroniser tout",
|
||||
"System": "Système",
|
||||
|
@ -288,12 +283,12 @@
|
|||
"Theme": "Thème",
|
||||
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Cela garantit que vos précieuses conversations sont en sécurité dans votre base de données. Merci !",
|
||||
"This setting does not sync across browsers or devices.": "Ce paramètre ne se synchronise pas entre les navigateurs ou les appareils.",
|
||||
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "",
|
||||
"Title": "Titre",
|
||||
"Title Auto-Generation": "Génération automatique de titre",
|
||||
"Title Generation Prompt": "Prompt de génération de titre",
|
||||
"to": "à",
|
||||
"To access the available model names for downloading,": "Pour accéder aux noms de modèles disponibles pour le téléchargement,",
|
||||
"to chat input.": "à l'entrée du chat.",
|
||||
"Toggle settings": "Basculer les paramètres",
|
||||
"Toggle sidebar": "Basculer la barre latérale",
|
||||
"Top K": "Top K",
|
||||
|
@ -301,12 +296,10 @@
|
|||
"Trouble accessing Ollama?": "Problèmes d'accès à Ollama ?",
|
||||
"TTS Settings": "Paramètres TTS",
|
||||
"Uh-oh! There was an issue connecting to {{provider}}.": "Uh-oh ! Il y a eu un problème de connexion à {{provider}}.",
|
||||
"Upload a GGUF model": "Téléverser un modèle GGUF",
|
||||
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "",
|
||||
"Upload files": "Téléverser des fichiers",
|
||||
"Upload Progress": "Progression du téléversement",
|
||||
"URL Mode": "Mode URL",
|
||||
"Use '#' in the prompt input to load and select your documents.": "Utilisez '#' dans l'entrée du prompt pour charger et sélectionner vos documents.",
|
||||
"user": "Utilisateur",
|
||||
"User": "",
|
||||
"User Permissions": "Permissions d'utilisateur",
|
||||
"Users": "Utilisateurs",
|
||||
"Utilize": "Utiliser",
|
||||
|
@ -320,7 +313,8 @@
|
|||
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Lorsque l'historique est désactivé, les nouveaux chats sur ce navigateur n'apparaîtront pas dans votre historique sur aucun de vos appareils.",
|
||||
"Whisper (Local)": "Chuchotement (Local)",
|
||||
"Write a prompt suggestion (e.g. Who are you?)": "Écrivez un prompt (e.x. Qui est-tu ?)",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword]": "Ecrivez un résumé en 50 mots [sujet ou mot-clé]",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword].": "Ecrivez un résumé en 50 mots [sujet ou mot-clé]",
|
||||
"You": "",
|
||||
"You're a helpful assistant.": "Vous êtes un assistant utile",
|
||||
"You're now logged in.": "Vous êtes maintenant connecté."
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' or '-1' для відсутності терміну дії.",
|
||||
"(Beta)": "(Beta)",
|
||||
"(e.g. `sh webui.sh --api`)": "(e.g. `sh webui.sh --api`)",
|
||||
"{{item}} not provided": "{{item}} не надано",
|
||||
"{{modelName}} is thinking...": "{{modelName}} думає...",
|
||||
|
@ -14,12 +15,12 @@
|
|||
"Add Docs": "Додати документи",
|
||||
"Add Files": "Додати файли",
|
||||
"Add LiteLLM Model": "Додати модель LiteLLM",
|
||||
"Add message": "Додати повідомлення",
|
||||
"add tags": "додати теги",
|
||||
"Adjusting these settings will apply changes universally to all users.": "Корегування цих налаштувань застосовуватиме зміни для всіх користувачів.",
|
||||
"admin": "адміністратор",
|
||||
"Admin": "Адмін",
|
||||
"Admin Panel": "Панель адміністратора",
|
||||
"Admin Settings": "Налаштування адміністратора",
|
||||
"Advanced": "Розширені",
|
||||
"Advanced Model Params": "Розширені параметри моделі",
|
||||
"Advanced Parameters": "Розширені параметри",
|
||||
"all": "всі",
|
||||
|
@ -43,6 +44,7 @@
|
|||
"Cancel": "Скасувати",
|
||||
"Categories": "Категорії",
|
||||
"Change Password": "Змінити пароль",
|
||||
"Chat": "Чат",
|
||||
"Chat History": "Історія чату",
|
||||
"Chat History is off for this browser.": "Історія чату вимкнена для цього браузера.",
|
||||
"Chats": "Чати",
|
||||
|
@ -68,6 +70,7 @@
|
|||
"Copy last code block": "Копіювати останній блок коду",
|
||||
"Copy last response": "Копіювати останню відповідь",
|
||||
"Copying to clipboard was successful!": "Копіювання в буфер обміну виконано успішно!",
|
||||
"Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "Створіть стислий, 3-5 слів заголовок для наступного запиту, суворо дотримуючись 3-5 слів обмеження та уникаючи використання слова 'заголовок':",
|
||||
"Create a modelfile": "Створити modelfile",
|
||||
"Create Account": "Створити обліковий запис",
|
||||
"Created at": "Створено",
|
||||
|
@ -83,7 +86,6 @@
|
|||
"Default (Web API)": "За замовчуванням (Web API)",
|
||||
"Default model updated": "Модель за замовчуванням оновлено",
|
||||
"Default Prompt Suggestions": "Запропоновані запити за замовчуванням",
|
||||
"Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "Створіть стислий, 3-5 слів заголовок для наступного запиту, суворо дотримуючись 3-5 слів обмеження та уникаючи використання слова 'заголовок':",
|
||||
"Default User Role": "Роль користувача за замовчуванням",
|
||||
"delete": "видалити",
|
||||
"Delete a model": "Видалити модель",
|
||||
|
@ -107,6 +109,7 @@
|
|||
"Don't have an account?": "Немає облікового запису?",
|
||||
"Download as a File": "Завантажити як файл",
|
||||
"Download Database": "Завантажити базу даних",
|
||||
"Drop any files here to add to the conversation": "Перетягніть сюди файли, щоб додати до розмови",
|
||||
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "напр. '30s','10m'. Дійсні одиниці часу: 'с', 'хв', 'г'.",
|
||||
"Edit Doc": "Редагувати документ",
|
||||
"Edit User": "Редагувати користувача",
|
||||
|
@ -119,15 +122,13 @@
|
|||
"Enter Your Email": "Введіть вашу електронну пошту",
|
||||
"Enter Your Full Name": "Введіть ваше повне ім'я",
|
||||
"Enter Your Password": "Введіть ваш пароль",
|
||||
"Experimental": "Експериментальний",
|
||||
"Export All Chats (All Users)": "Експортувати всі чати (всі користувачі)",
|
||||
"Export Chats": "Експортувати чати",
|
||||
"Export Documents Mapping": "Експортувати відображення документів",
|
||||
"Export Modelfiles": "Експортувати modelfiles",
|
||||
"Export Prompts": "Експортувати запити",
|
||||
"Failed to read clipboard contents": "Не вдалося прочитати вміст буфера обміну",
|
||||
"File Mode": "Режим файлу",
|
||||
"File not found.`": "Файл не знайдено.`",
|
||||
"File not found.": "Файл не знайдено.",
|
||||
"Focus chat input": "Фокус вводу чату",
|
||||
"Format your variables using square brackets like this:": "Форматуйте свої змінні квадратними дужками так:",
|
||||
"From (Base Model)": "Від (базова модель)",
|
||||
|
@ -169,36 +170,36 @@
|
|||
"Mirostat Eta": "Mirostat Eta",
|
||||
"Mirostat Tau": "Mirostat Tau",
|
||||
"MMMM DD, YYYY": "MMMM ДД, РРРР",
|
||||
"Model '{{modelName}}' has been successfully downloaded.`": "Модель '{{modelName}}' успішно завантажено.`",
|
||||
"Model '{{modelName}}' has been successfully downloaded.": "Модель '{{modelName}}' успішно завантажено.",
|
||||
"Model '{{modelTag}}' is already in queue for downloading.": "Модель '{{modelTag}}' вже знаходиться в черзі на завантаження.",
|
||||
"Model {{modelId}} not found": "Модель {{modelId}} не знайдено",
|
||||
"Model {{modelName}} already exists.": "Модель {{modelName}} вже існує.",
|
||||
"Model Name": "Назва моделі",
|
||||
"Model not selected": "Модель не вибрана",
|
||||
"Model Tag Name": "Ім'я тегу моделі",
|
||||
"Modelfile": "Modelfile",
|
||||
"Modelfile": "Файли моделі",
|
||||
"Modelfile Advanced Settings": "Розширені налаштування modelfile",
|
||||
"Modelfile Content": "Зміст modelfile",
|
||||
"Modelfiles": "Modelfiles",
|
||||
"Modelfiles": "Файли моделей",
|
||||
"Models": "Моделі",
|
||||
"My Documents": "Мої документи",
|
||||
"My Modelfiles": "Мої modelfiles",
|
||||
"My Modelfiles": "Мої файли моделей",
|
||||
"My Prompts": "Мої запити",
|
||||
"Name": "Назва",
|
||||
"Name Tag": "Назва тегу",
|
||||
"Name your Modelfile": "Назвіть свій modelfile",
|
||||
"Name your modelfile": "Назвіть свій файл моделі",
|
||||
"New Chat": "Новий чат",
|
||||
"New Password": "Новий пароль",
|
||||
"Not sure what to add?": "Не впевнений, що додати?",
|
||||
"Not sure what to write? Switch to": "Не впевнений, що писати? Переключитися на",
|
||||
"Off": "Вимк",
|
||||
"Okay, Let's Go!": "Гаразд, давайте почнемо!",
|
||||
"Ollama API URL": "URL API Ollama",
|
||||
"Ollama Version": "Версія Ollama",
|
||||
"On": "Увімк",
|
||||
"Only": "Тільки",
|
||||
"Only alphanumeric characters and hyphens are allowed in the command string.": "У рядку команди дозволено використовувати лише алфавітно-цифрові символи та дефіси.",
|
||||
"Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "Ой! Зачекайте, будь ласка! Ваші файли ще готуються. Ми робимо все, щоб вони були ідеальними. Будь ласка, будьте терплячі, ми повідомимо вам, коли вони будуть готові.",
|
||||
"Oops! Looks like the URL is invalid. Please double-check and try again.": "Упс! Схоже, що URL-адреса невірна. Будь ласка, перевірте ще раз та спробуйте ще раз.",
|
||||
"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Упс! Ви використовуєте непідтримуваний метод (тільки для фронтенду). Будь ласка, обслуговуйте WebUI з бекенду.",
|
||||
"Open": "Відкрити",
|
||||
"Open AI": "Open AI",
|
||||
"Open new chat": "Відкрити новий чат",
|
||||
|
@ -206,8 +207,9 @@
|
|||
"or": "або",
|
||||
"Parameters": "Параметри",
|
||||
"Password": "Пароль",
|
||||
"pending": "очікування",
|
||||
"Pending": "На розгляді",
|
||||
"Permission denied when accessing microphone: {{error}}": "Доступ до мікрофона заборонено: {{error}}",
|
||||
"Playground": "Майданчик",
|
||||
"Profile": "Профіль",
|
||||
"Prompt Content": "Зміст запиту",
|
||||
"Prompt suggestions": "Швидкі запити",
|
||||
|
@ -265,38 +267,39 @@
|
|||
"SpeechRecognition API is not supported in this browser.": "SpeechRecognition API не підтримується в цьому браузері.",
|
||||
"Stop Sequence": "Символ зупинки",
|
||||
"STT Settings": "Налаштування STT",
|
||||
"Submit": "Надіслати",
|
||||
"Success": "Успіх",
|
||||
"Successfully updated": "Успішно оновлено",
|
||||
"Successfully updated.": "Успішно оновлено.",
|
||||
"Sync All": "Синхронізувати все",
|
||||
"System": "Система",
|
||||
"System Prompt": "Системний запит",
|
||||
"Tags": "Теги",
|
||||
"Temperature": "Температура",
|
||||
"Template": "Шаблон",
|
||||
"Text Completion": "Завершення тексту",
|
||||
"Text-to-Speech Engine": "Система синтезу мови",
|
||||
"Tfs Z": "Tfs Z",
|
||||
"Theme": "Тема",
|
||||
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Це забезпечує збереження ваших цінних розмов у безпечному бекенд-сховищі. Дякуємо!",
|
||||
"This setting does not sync across browsers or devices.": "Це налаштування не синхронізується між браузерами або пристроями.",
|
||||
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "",
|
||||
"Title": "Заголовок",
|
||||
"Title Auto-Generation": "Автогенерація заголовків",
|
||||
"Title Generation Prompt": "Запит на генерування заголовків",
|
||||
"to": "до",
|
||||
"To access the available model names for downloading,": "Щоб отримати доступ до назв доступних для завантаження моделей,",
|
||||
"to chat input.": "до введення чату.",
|
||||
"Toggle settings": "Переключити налаштування",
|
||||
"Toggle sidebar": "Переключити бокову панель",
|
||||
"Top K": "Вершина K",
|
||||
"Top P": "Вершина P",
|
||||
"Top K": "Top K",
|
||||
"Top P": "Top P",
|
||||
"Trouble accessing Ollama?": "Проблеми з доступом до Ollama?",
|
||||
"TTS Settings": "Налаштування TTS",
|
||||
"Uh-oh! There was an issue connecting to {{provider}}.": "Ой! Виникла проблема при підключенні до {{provider}}.",
|
||||
"Upload a GGUF model": "Завантажити модель GGUF",
|
||||
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Невідомий тип файлу '{{file_type}}', але приймається та обробляється як звичайний текст",
|
||||
"Upload files": "Завантажити файли",
|
||||
"Upload Progress": "Прогрес завантаження",
|
||||
"URL Mode": "Режим URL",
|
||||
"Use '#' in the prompt input to load and select your documents.": "Використовуйте '#' у введенні запиту для завантаження та вибору ваших документів.",
|
||||
"user": "користувач",
|
||||
"User": "Користувач",
|
||||
"User Permissions": "Дозволи користувача",
|
||||
"Users": "Користувачі",
|
||||
"Utilize": "Використовувати",
|
||||
|
@ -308,19 +311,10 @@
|
|||
"WebUI Settings": "Налаштування WebUI",
|
||||
"What’s New in": "Що нового в",
|
||||
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Коли історія вимкнена, нові чати в цьому браузері не будуть відображатися в історії на жодному з ваших пристроїв.",
|
||||
"Whisper (Local)": "Шепіт (локально)",
|
||||
"Whisper (Local)": "Whisper (локально)",
|
||||
"Write a prompt suggestion (e.g. Who are you?)": "Напишіть запит (напр. Хто ти?)",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword]": "Напишіть стислий зміст у 50 слів, який узагальнює [тему або ключове слово]",
|
||||
"You're now logged in.": "Ви увійшли в систему.",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword].": "Напишіть стислий зміст у 50 слів, який узагальнює [тема або ключове слово].",
|
||||
"You": "Ви",
|
||||
"Playground": "Майданчик",
|
||||
"Add message": "Додати повідомлення",
|
||||
"Enter a user message here": "Введіть тут повідомлення користувача",
|
||||
"Enter an assistant message here": "Введіть тут повідомлення асистента",
|
||||
"Drop any files here to add to the conversation": "Перетягніть сюди файли, щоб додати до розмови",
|
||||
"You're a helpful assistant.": "Ви корисний асистент.",
|
||||
"assistant": "асистент",
|
||||
"Submit": "Надіслати",
|
||||
"Chat": "Чат",
|
||||
"Text Completion": "Завершення тексту"
|
||||
"You're now logged in.": "Ви увійшли в систему."
|
||||
}
|
||||
|
|
|
@ -99,14 +99,11 @@
|
|||
if (localDBChats.length === 0) {
|
||||
await deleteDB('Chats');
|
||||
}
|
||||
|
||||
console.log('localdb', localDBChats);
|
||||
}
|
||||
|
||||
console.log(DB);
|
||||
} catch (error) {
|
||||
// IndexedDB Not Found
|
||||
console.log('IDB Not Found');
|
||||
}
|
||||
|
||||
console.log();
|
||||
|
|
|
@ -344,7 +344,7 @@
|
|||
content: $settings.system
|
||||
}
|
||||
: undefined,
|
||||
...messages.filter((message) => !message.deleted)
|
||||
...messages
|
||||
]
|
||||
.filter((message) => message)
|
||||
.map((message, idx, arr) => ({
|
||||
|
@ -558,7 +558,7 @@
|
|||
content: $settings.system
|
||||
}
|
||||
: undefined,
|
||||
...messages.filter((message) => !message.deleted)
|
||||
...messages
|
||||
]
|
||||
.filter((message) => message)
|
||||
.map((message, idx, arr) => ({
|
||||
|
|
|
@ -354,7 +354,7 @@
|
|||
content: $settings.system
|
||||
}
|
||||
: undefined,
|
||||
...messages.filter((message) => !message.deleted)
|
||||
...messages
|
||||
]
|
||||
.filter((message) => message)
|
||||
.map((message, idx, arr) => ({
|
||||
|
@ -568,7 +568,7 @@
|
|||
content: $settings.system
|
||||
}
|
||||
: undefined,
|
||||
...messages.filter((message) => !message.deleted)
|
||||
...messages
|
||||
]
|
||||
.filter((message) => message)
|
||||
.map((message, idx, arr) => ({
|
||||
|
|
|
@ -562,9 +562,9 @@ SYSTEM """${system}"""`.replace(/^\s*\n/gm, '');
|
|||
}}
|
||||
>
|
||||
{#if advanced}
|
||||
<span class="ml-2 self-center">{$i18n.t(' Custom ')}</span>
|
||||
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
|
||||
{:else}
|
||||
<span class="ml-2 self-center">{$i18n.t(' Default ')}</span>
|
||||
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -181,7 +181,7 @@
|
|||
<textarea
|
||||
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
|
||||
placeholder={$i18n.t(
|
||||
'Write a summary in 50 words that summarizes [topic or keyword]'
|
||||
'Write a summary in 50 words that summarizes [topic or keyword].'
|
||||
)}
|
||||
rows="6"
|
||||
bind:value={content}
|
||||
|
|
Loading…
Reference in a new issue