Spaces:
Running
Running
0.4.3
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- CHANGELOG.md +17 -0
- backend/open_webui/apps/ollama/main.py +4 -2
- backend/open_webui/apps/openai/main.py +6 -0
- backend/open_webui/apps/retrieval/main.py +45 -11
- backend/open_webui/apps/retrieval/utils.py +7 -27
- backend/open_webui/apps/retrieval/web/mojeek.py +40 -0
- backend/open_webui/apps/webui/routers/auths.py +14 -4
- backend/open_webui/apps/webui/routers/files.py +1 -1
- backend/open_webui/apps/webui/routers/tools.py +25 -29
- backend/open_webui/config.py +27 -10
- backend/open_webui/main.py +67 -36
- backend/open_webui/utils/tools.py +79 -88
- package-lock.json +945 -18
- package.json +9 -1
- src/app.css +72 -5
- src/lib/apis/streaming/index.ts +4 -4
- src/lib/components/admin/Settings/Connections/OpenAIConnection.svelte +1 -1
- src/lib/components/admin/Settings/Models.svelte +1 -1
- src/lib/components/admin/Settings/WebSearch.svelte +12 -0
- src/lib/components/chat/Chat.svelte +13 -13
- src/lib/components/chat/MessageInput.svelte +20 -51
- src/lib/components/chat/Messages/Citations.svelte +36 -27
- src/lib/components/chat/Messages/ContentRenderer.svelte +29 -0
- src/lib/components/chat/Messages/Markdown.svelte +5 -1
- src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte +8 -4
- src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte +15 -4
- src/lib/components/chat/Messages/Markdown/Source.svelte +25 -0
- src/lib/components/chat/Messages/RateComment.svelte +1 -1
- src/lib/components/chat/Messages/ResponseMessage.svelte +12 -3
- src/lib/components/chat/Messages/UserMessage.svelte +1 -5
- src/lib/components/common/RichTextInput.svelte +201 -412
- src/lib/components/workspace/Knowledge/KnowledgeBase.svelte +1 -1
- src/lib/i18n/locales/ar-BH/translation.json +2 -0
- src/lib/i18n/locales/bg-BG/translation.json +2 -0
- src/lib/i18n/locales/bn-BD/translation.json +2 -0
- src/lib/i18n/locales/ca-ES/translation.json +2 -0
- src/lib/i18n/locales/ceb-PH/translation.json +2 -0
- src/lib/i18n/locales/cs-CZ/translation.json +2 -0
- src/lib/i18n/locales/da-DK/translation.json +2 -0
- src/lib/i18n/locales/de-DE/translation.json +2 -0
- src/lib/i18n/locales/dg-DG/translation.json +2 -0
- src/lib/i18n/locales/en-GB/translation.json +2 -0
- src/lib/i18n/locales/en-US/translation.json +2 -0
- src/lib/i18n/locales/es-ES/translation.json +2 -0
- src/lib/i18n/locales/fa-IR/translation.json +2 -0
- src/lib/i18n/locales/fi-FI/translation.json +2 -0
- src/lib/i18n/locales/fr-CA/translation.json +2 -0
- src/lib/i18n/locales/fr-FR/translation.json +2 -0
- src/lib/i18n/locales/he-IL/translation.json +2 -0
- src/lib/i18n/locales/hi-IN/translation.json +2 -0
CHANGELOG.md
CHANGED
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
|
|
5 |
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
6 |
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
## [0.4.2] - 2024-11-20
|
9 |
|
10 |
### Fixed
|
|
|
5 |
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
6 |
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7 |
|
8 |
+
## [0.4.3] - 2024-11-21
|
9 |
+
|
10 |
+
### Added
|
11 |
+
|
12 |
+
- **📚 Inline Citations for RAG Results**: Get seamless inline citations for Retrieval-Augmented Generation (RAG) responses using the default RAG prompt. Note: This feature only supports newly uploaded files, improving traceability and providing source clarity.
|
13 |
+
- **🎨 Better Rich Text Input Support**: Enjoy smoother and more reliable rich text formatting for chats, enhancing communication quality.
|
14 |
+
- **⚡ Faster Model Retrieval**: Implemented caching optimizations for faster model loading, providing a noticeable speed boost across workflows. Further improvements are on the way!
|
15 |
+
|
16 |
+
### Fixed
|
17 |
+
|
18 |
+
- **🔗 Pipelines Feature Restored**: Resolved a critical issue that previously prevented Pipelines from functioning, ensuring seamless workflows.
|
19 |
+
- **✏️ Missing Suffix Field in Ollama Form**: Added the missing "suffix" field to the Ollama generate form, enhancing customization options.
|
20 |
+
|
21 |
+
### Changed
|
22 |
+
|
23 |
+
- **🗂️ Renamed "Citations" to "Sources"**: Improved clarity and consistency by renaming the "citations" field to "sources" in messages.
|
24 |
+
|
25 |
## [0.4.2] - 2024-11-20
|
26 |
|
27 |
### Fixed
|
backend/open_webui/apps/ollama/main.py
CHANGED
@@ -9,6 +9,8 @@ from typing import Optional, Union
|
|
9 |
from urllib.parse import urlparse
|
10 |
|
11 |
import aiohttp
|
|
|
|
|
12 |
import requests
|
13 |
from open_webui.apps.webui.models.models import Models
|
14 |
from open_webui.config import (
|
@@ -256,6 +258,7 @@ def merge_models_lists(model_lists):
|
|
256 |
return list(merged_models.values())
|
257 |
|
258 |
|
|
|
259 |
async def get_all_models():
|
260 |
log.info("get_all_models()")
|
261 |
if app.state.config.ENABLE_OLLAMA_API:
|
@@ -295,8 +298,6 @@ async def get_all_models():
|
|
295 |
for model in response.get("models", []):
|
296 |
model["model"] = f"{prefix_id}.{model['model']}"
|
297 |
|
298 |
-
print(responses)
|
299 |
-
|
300 |
models = {
|
301 |
"models": merge_models_lists(
|
302 |
map(
|
@@ -837,6 +838,7 @@ async def generate_ollama_batch_embeddings(
|
|
837 |
class GenerateCompletionForm(BaseModel):
|
838 |
model: str
|
839 |
prompt: str
|
|
|
840 |
images: Optional[list[str]] = None
|
841 |
format: Optional[str] = None
|
842 |
options: Optional[dict] = None
|
|
|
9 |
from urllib.parse import urlparse
|
10 |
|
11 |
import aiohttp
|
12 |
+
from aiocache import cached
|
13 |
+
|
14 |
import requests
|
15 |
from open_webui.apps.webui.models.models import Models
|
16 |
from open_webui.config import (
|
|
|
258 |
return list(merged_models.values())
|
259 |
|
260 |
|
261 |
+
@cached(ttl=3)
|
262 |
async def get_all_models():
|
263 |
log.info("get_all_models()")
|
264 |
if app.state.config.ENABLE_OLLAMA_API:
|
|
|
298 |
for model in response.get("models", []):
|
299 |
model["model"] = f"{prefix_id}.{model['model']}"
|
300 |
|
|
|
|
|
301 |
models = {
|
302 |
"models": merge_models_lists(
|
303 |
map(
|
|
|
838 |
class GenerateCompletionForm(BaseModel):
|
839 |
model: str
|
840 |
prompt: str
|
841 |
+
suffix: Optional[str] = None
|
842 |
images: Optional[list[str]] = None
|
843 |
format: Optional[str] = None
|
844 |
options: Optional[dict] = None
|
backend/open_webui/apps/openai/main.py
CHANGED
@@ -6,7 +6,10 @@ from pathlib import Path
|
|
6 |
from typing import Literal, Optional, overload
|
7 |
|
8 |
import aiohttp
|
|
|
9 |
import requests
|
|
|
|
|
10 |
from open_webui.apps.webui.models.models import Models
|
11 |
from open_webui.config import (
|
12 |
CACHE_DIR,
|
@@ -302,6 +305,8 @@ async def get_all_models_responses() -> list:
|
|
302 |
}
|
303 |
|
304 |
tasks.append(asyncio.ensure_future(asyncio.sleep(0, model_list)))
|
|
|
|
|
305 |
|
306 |
responses = await asyncio.gather(*tasks)
|
307 |
|
@@ -323,6 +328,7 @@ async def get_all_models_responses() -> list:
|
|
323 |
return responses
|
324 |
|
325 |
|
|
|
326 |
async def get_all_models() -> dict[str, list]:
|
327 |
log.info("get_all_models()")
|
328 |
|
|
|
6 |
from typing import Literal, Optional, overload
|
7 |
|
8 |
import aiohttp
|
9 |
+
from aiocache import cached
|
10 |
import requests
|
11 |
+
|
12 |
+
|
13 |
from open_webui.apps.webui.models.models import Models
|
14 |
from open_webui.config import (
|
15 |
CACHE_DIR,
|
|
|
305 |
}
|
306 |
|
307 |
tasks.append(asyncio.ensure_future(asyncio.sleep(0, model_list)))
|
308 |
+
else:
|
309 |
+
tasks.append(asyncio.ensure_future(asyncio.sleep(0, None)))
|
310 |
|
311 |
responses = await asyncio.gather(*tasks)
|
312 |
|
|
|
328 |
return responses
|
329 |
|
330 |
|
331 |
+
@cached(ttl=3)
|
332 |
async def get_all_models() -> dict[str, list]:
|
333 |
log.info("get_all_models()")
|
334 |
|
backend/open_webui/apps/retrieval/main.py
CHANGED
@@ -29,6 +29,7 @@ from open_webui.apps.retrieval.loaders.youtube import YoutubeLoader
|
|
29 |
from open_webui.apps.retrieval.web.main import SearchResult
|
30 |
from open_webui.apps.retrieval.web.utils import get_web_loader
|
31 |
from open_webui.apps.retrieval.web.brave import search_brave
|
|
|
32 |
from open_webui.apps.retrieval.web.duckduckgo import search_duckduckgo
|
33 |
from open_webui.apps.retrieval.web.google_pse import search_google_pse
|
34 |
from open_webui.apps.retrieval.web.jina_search import search_jina
|
@@ -53,6 +54,7 @@ from open_webui.apps.retrieval.utils import (
|
|
53 |
from open_webui.apps.webui.models.files import Files
|
54 |
from open_webui.config import (
|
55 |
BRAVE_SEARCH_API_KEY,
|
|
|
56 |
TIKTOKEN_ENCODING_NAME,
|
57 |
RAG_TEXT_SPLITTER,
|
58 |
CHUNK_OVERLAP,
|
@@ -180,6 +182,7 @@ app.state.config.SEARXNG_QUERY_URL = SEARXNG_QUERY_URL
|
|
180 |
app.state.config.GOOGLE_PSE_API_KEY = GOOGLE_PSE_API_KEY
|
181 |
app.state.config.GOOGLE_PSE_ENGINE_ID = GOOGLE_PSE_ENGINE_ID
|
182 |
app.state.config.BRAVE_SEARCH_API_KEY = BRAVE_SEARCH_API_KEY
|
|
|
183 |
app.state.config.SERPSTACK_API_KEY = SERPSTACK_API_KEY
|
184 |
app.state.config.SERPSTACK_HTTPS = SERPSTACK_HTTPS
|
185 |
app.state.config.SERPER_API_KEY = SERPER_API_KEY
|
@@ -478,6 +481,7 @@ async def get_rag_config(user=Depends(get_admin_user)):
|
|
478 |
"google_pse_api_key": app.state.config.GOOGLE_PSE_API_KEY,
|
479 |
"google_pse_engine_id": app.state.config.GOOGLE_PSE_ENGINE_ID,
|
480 |
"brave_search_api_key": app.state.config.BRAVE_SEARCH_API_KEY,
|
|
|
481 |
"serpstack_api_key": app.state.config.SERPSTACK_API_KEY,
|
482 |
"serpstack_https": app.state.config.SERPSTACK_HTTPS,
|
483 |
"serper_api_key": app.state.config.SERPER_API_KEY,
|
@@ -523,6 +527,7 @@ class WebSearchConfig(BaseModel):
|
|
523 |
google_pse_api_key: Optional[str] = None
|
524 |
google_pse_engine_id: Optional[str] = None
|
525 |
brave_search_api_key: Optional[str] = None
|
|
|
526 |
serpstack_api_key: Optional[str] = None
|
527 |
serpstack_https: Optional[bool] = None
|
528 |
serper_api_key: Optional[str] = None
|
@@ -593,6 +598,9 @@ async def update_rag_config(form_data: ConfigUpdateForm, user=Depends(get_admin_
|
|
593 |
app.state.config.BRAVE_SEARCH_API_KEY = (
|
594 |
form_data.web.search.brave_search_api_key
|
595 |
)
|
|
|
|
|
|
|
596 |
app.state.config.SERPSTACK_API_KEY = form_data.web.search.serpstack_api_key
|
597 |
app.state.config.SERPSTACK_HTTPS = form_data.web.search.serpstack_https
|
598 |
app.state.config.SERPER_API_KEY = form_data.web.search.serper_api_key
|
@@ -643,6 +651,7 @@ async def update_rag_config(form_data: ConfigUpdateForm, user=Depends(get_admin_
|
|
643 |
"google_pse_api_key": app.state.config.GOOGLE_PSE_API_KEY,
|
644 |
"google_pse_engine_id": app.state.config.GOOGLE_PSE_ENGINE_ID,
|
645 |
"brave_search_api_key": app.state.config.BRAVE_SEARCH_API_KEY,
|
|
|
646 |
"serpstack_api_key": app.state.config.SERPSTACK_API_KEY,
|
647 |
"serpstack_https": app.state.config.SERPSTACK_HTTPS,
|
648 |
"serper_api_key": app.state.config.SERPER_API_KEY,
|
@@ -884,19 +893,17 @@ def process_file(
|
|
884 |
# Update the content in the file
|
885 |
# Usage: /files/{file_id}/data/content/update
|
886 |
|
887 |
-
VECTOR_DB_CLIENT.
|
888 |
-
collection_name=f"file-{file.id}",
|
889 |
-
filter={"file_id": file.id},
|
890 |
-
)
|
891 |
|
892 |
docs = [
|
893 |
Document(
|
894 |
page_content=form_data.content,
|
895 |
metadata={
|
896 |
-
|
|
|
897 |
"created_by": file.user_id,
|
898 |
"file_id": file.id,
|
899 |
-
|
900 |
},
|
901 |
)
|
902 |
]
|
@@ -923,10 +930,11 @@ def process_file(
|
|
923 |
Document(
|
924 |
page_content=file.data.get("content", ""),
|
925 |
metadata={
|
926 |
-
|
|
|
927 |
"created_by": file.user_id,
|
928 |
"file_id": file.id,
|
929 |
-
|
930 |
},
|
931 |
)
|
932 |
]
|
@@ -946,15 +954,30 @@ def process_file(
|
|
946 |
docs = loader.load(
|
947 |
file.filename, file.meta.get("content_type"), file_path
|
948 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
949 |
else:
|
950 |
docs = [
|
951 |
Document(
|
952 |
page_content=file.data.get("content", ""),
|
953 |
metadata={
|
|
|
954 |
"name": file.filename,
|
955 |
"created_by": file.user_id,
|
956 |
"file_id": file.id,
|
957 |
-
|
958 |
},
|
959 |
)
|
960 |
]
|
@@ -975,7 +998,7 @@ def process_file(
|
|
975 |
collection_name=collection_name,
|
976 |
metadata={
|
977 |
"file_id": file.id,
|
978 |
-
"name": file.
|
979 |
"hash": hash,
|
980 |
},
|
981 |
add=(True if form_data.collection_name else False),
|
@@ -992,7 +1015,7 @@ def process_file(
|
|
992 |
return {
|
993 |
"status": True,
|
994 |
"collection_name": collection_name,
|
995 |
-
"filename": file.
|
996 |
"content": text_content,
|
997 |
}
|
998 |
except Exception as e:
|
@@ -1131,6 +1154,7 @@ def search_web(engine: str, query: str) -> list[SearchResult]:
|
|
1131 |
- SEARXNG_QUERY_URL
|
1132 |
- GOOGLE_PSE_API_KEY + GOOGLE_PSE_ENGINE_ID
|
1133 |
- BRAVE_SEARCH_API_KEY
|
|
|
1134 |
- SERPSTACK_API_KEY
|
1135 |
- SERPER_API_KEY
|
1136 |
- SERPLY_API_KEY
|
@@ -1177,6 +1201,16 @@ def search_web(engine: str, query: str) -> list[SearchResult]:
|
|
1177 |
)
|
1178 |
else:
|
1179 |
raise Exception("No BRAVE_SEARCH_API_KEY found in environment variables")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1180 |
elif engine == "serpstack":
|
1181 |
if app.state.config.SERPSTACK_API_KEY:
|
1182 |
return search_serpstack(
|
|
|
29 |
from open_webui.apps.retrieval.web.main import SearchResult
|
30 |
from open_webui.apps.retrieval.web.utils import get_web_loader
|
31 |
from open_webui.apps.retrieval.web.brave import search_brave
|
32 |
+
from open_webui.apps.retrieval.web.mojeek import search_mojeek
|
33 |
from open_webui.apps.retrieval.web.duckduckgo import search_duckduckgo
|
34 |
from open_webui.apps.retrieval.web.google_pse import search_google_pse
|
35 |
from open_webui.apps.retrieval.web.jina_search import search_jina
|
|
|
54 |
from open_webui.apps.webui.models.files import Files
|
55 |
from open_webui.config import (
|
56 |
BRAVE_SEARCH_API_KEY,
|
57 |
+
MOJEEK_SEARCH_API_KEY,
|
58 |
TIKTOKEN_ENCODING_NAME,
|
59 |
RAG_TEXT_SPLITTER,
|
60 |
CHUNK_OVERLAP,
|
|
|
182 |
app.state.config.GOOGLE_PSE_API_KEY = GOOGLE_PSE_API_KEY
|
183 |
app.state.config.GOOGLE_PSE_ENGINE_ID = GOOGLE_PSE_ENGINE_ID
|
184 |
app.state.config.BRAVE_SEARCH_API_KEY = BRAVE_SEARCH_API_KEY
|
185 |
+
app.state.config.MOJEEK_SEARCH_API_KEY = MOJEEK_SEARCH_API_KEY
|
186 |
app.state.config.SERPSTACK_API_KEY = SERPSTACK_API_KEY
|
187 |
app.state.config.SERPSTACK_HTTPS = SERPSTACK_HTTPS
|
188 |
app.state.config.SERPER_API_KEY = SERPER_API_KEY
|
|
|
481 |
"google_pse_api_key": app.state.config.GOOGLE_PSE_API_KEY,
|
482 |
"google_pse_engine_id": app.state.config.GOOGLE_PSE_ENGINE_ID,
|
483 |
"brave_search_api_key": app.state.config.BRAVE_SEARCH_API_KEY,
|
484 |
+
"mojeek_search_api_key": app.state.config.MOJEEK_SEARCH_API_KEY,
|
485 |
"serpstack_api_key": app.state.config.SERPSTACK_API_KEY,
|
486 |
"serpstack_https": app.state.config.SERPSTACK_HTTPS,
|
487 |
"serper_api_key": app.state.config.SERPER_API_KEY,
|
|
|
527 |
google_pse_api_key: Optional[str] = None
|
528 |
google_pse_engine_id: Optional[str] = None
|
529 |
brave_search_api_key: Optional[str] = None
|
530 |
+
mojeek_search_api_key: Optional[str] = None
|
531 |
serpstack_api_key: Optional[str] = None
|
532 |
serpstack_https: Optional[bool] = None
|
533 |
serper_api_key: Optional[str] = None
|
|
|
598 |
app.state.config.BRAVE_SEARCH_API_KEY = (
|
599 |
form_data.web.search.brave_search_api_key
|
600 |
)
|
601 |
+
app.state.config.MOJEEK_SEARCH_API_KEY = (
|
602 |
+
form_data.web.search.mojeek_search_api_key
|
603 |
+
)
|
604 |
app.state.config.SERPSTACK_API_KEY = form_data.web.search.serpstack_api_key
|
605 |
app.state.config.SERPSTACK_HTTPS = form_data.web.search.serpstack_https
|
606 |
app.state.config.SERPER_API_KEY = form_data.web.search.serper_api_key
|
|
|
651 |
"google_pse_api_key": app.state.config.GOOGLE_PSE_API_KEY,
|
652 |
"google_pse_engine_id": app.state.config.GOOGLE_PSE_ENGINE_ID,
|
653 |
"brave_search_api_key": app.state.config.BRAVE_SEARCH_API_KEY,
|
654 |
+
"mojeek_search_api_key": app.state.config.MOJEEK_SEARCH_API_KEY,
|
655 |
"serpstack_api_key": app.state.config.SERPSTACK_API_KEY,
|
656 |
"serpstack_https": app.state.config.SERPSTACK_HTTPS,
|
657 |
"serper_api_key": app.state.config.SERPER_API_KEY,
|
|
|
893 |
# Update the content in the file
|
894 |
# Usage: /files/{file_id}/data/content/update
|
895 |
|
896 |
+
VECTOR_DB_CLIENT.delete_collection(collection_name=f"file-{file.id}")
|
|
|
|
|
|
|
897 |
|
898 |
docs = [
|
899 |
Document(
|
900 |
page_content=form_data.content,
|
901 |
metadata={
|
902 |
+
**file.meta,
|
903 |
+
"name": file.filename,
|
904 |
"created_by": file.user_id,
|
905 |
"file_id": file.id,
|
906 |
+
"source": file.filename,
|
907 |
},
|
908 |
)
|
909 |
]
|
|
|
930 |
Document(
|
931 |
page_content=file.data.get("content", ""),
|
932 |
metadata={
|
933 |
+
**file.meta,
|
934 |
+
"name": file.filename,
|
935 |
"created_by": file.user_id,
|
936 |
"file_id": file.id,
|
937 |
+
"source": file.filename,
|
938 |
},
|
939 |
)
|
940 |
]
|
|
|
954 |
docs = loader.load(
|
955 |
file.filename, file.meta.get("content_type"), file_path
|
956 |
)
|
957 |
+
|
958 |
+
docs = [
|
959 |
+
Document(
|
960 |
+
page_content=doc.page_content,
|
961 |
+
metadata={
|
962 |
+
**doc.metadata,
|
963 |
+
"name": file.filename,
|
964 |
+
"created_by": file.user_id,
|
965 |
+
"file_id": file.id,
|
966 |
+
"source": file.filename,
|
967 |
+
},
|
968 |
+
)
|
969 |
+
for doc in docs
|
970 |
+
]
|
971 |
else:
|
972 |
docs = [
|
973 |
Document(
|
974 |
page_content=file.data.get("content", ""),
|
975 |
metadata={
|
976 |
+
**file.meta,
|
977 |
"name": file.filename,
|
978 |
"created_by": file.user_id,
|
979 |
"file_id": file.id,
|
980 |
+
"source": file.filename,
|
981 |
},
|
982 |
)
|
983 |
]
|
|
|
998 |
collection_name=collection_name,
|
999 |
metadata={
|
1000 |
"file_id": file.id,
|
1001 |
+
"name": file.filename,
|
1002 |
"hash": hash,
|
1003 |
},
|
1004 |
add=(True if form_data.collection_name else False),
|
|
|
1015 |
return {
|
1016 |
"status": True,
|
1017 |
"collection_name": collection_name,
|
1018 |
+
"filename": file.filename,
|
1019 |
"content": text_content,
|
1020 |
}
|
1021 |
except Exception as e:
|
|
|
1154 |
- SEARXNG_QUERY_URL
|
1155 |
- GOOGLE_PSE_API_KEY + GOOGLE_PSE_ENGINE_ID
|
1156 |
- BRAVE_SEARCH_API_KEY
|
1157 |
+
- MOJEEK_SEARCH_API_KEY
|
1158 |
- SERPSTACK_API_KEY
|
1159 |
- SERPER_API_KEY
|
1160 |
- SERPLY_API_KEY
|
|
|
1201 |
)
|
1202 |
else:
|
1203 |
raise Exception("No BRAVE_SEARCH_API_KEY found in environment variables")
|
1204 |
+
elif engine == "mojeek":
|
1205 |
+
if app.state.config.MOJEEK_SEARCH_API_KEY:
|
1206 |
+
return search_mojeek(
|
1207 |
+
app.state.config.MOJEEK_SEARCH_API_KEY,
|
1208 |
+
query,
|
1209 |
+
app.state.config.RAG_WEB_SEARCH_RESULT_COUNT,
|
1210 |
+
app.state.config.RAG_WEB_SEARCH_DOMAIN_FILTER_LIST,
|
1211 |
+
)
|
1212 |
+
else:
|
1213 |
+
raise Exception("No MOJEEK_SEARCH_API_KEY found in environment variables")
|
1214 |
elif engine == "serpstack":
|
1215 |
if app.state.config.SERPSTACK_API_KEY:
|
1216 |
return search_serpstack(
|
backend/open_webui/apps/retrieval/utils.py
CHANGED
@@ -307,7 +307,7 @@ def get_embedding_function(
|
|
307 |
return lambda query: generate_multiple(query, func)
|
308 |
|
309 |
|
310 |
-
def
|
311 |
files,
|
312 |
queries,
|
313 |
embedding_function,
|
@@ -387,43 +387,24 @@ def get_rag_context(
|
|
387 |
del file["data"]
|
388 |
relevant_contexts.append({**context, "file": file})
|
389 |
|
390 |
-
|
391 |
-
citations = []
|
392 |
for context in relevant_contexts:
|
393 |
try:
|
394 |
if "documents" in context:
|
395 |
-
file_names = list(
|
396 |
-
set(
|
397 |
-
[
|
398 |
-
metadata["name"]
|
399 |
-
for metadata in context["metadatas"][0]
|
400 |
-
if metadata is not None and "name" in metadata
|
401 |
-
]
|
402 |
-
)
|
403 |
-
)
|
404 |
-
contexts.append(
|
405 |
-
((", ".join(file_names) + ":\n\n") if file_names else "")
|
406 |
-
+ "\n\n".join(
|
407 |
-
[text for text in context["documents"][0] if text is not None]
|
408 |
-
)
|
409 |
-
)
|
410 |
-
|
411 |
if "metadatas" in context:
|
412 |
-
|
413 |
"source": context["file"],
|
414 |
"document": context["documents"][0],
|
415 |
"metadata": context["metadatas"][0],
|
416 |
}
|
417 |
if "distances" in context and context["distances"]:
|
418 |
-
|
419 |
-
|
|
|
420 |
except Exception as e:
|
421 |
log.exception(e)
|
422 |
|
423 |
-
|
424 |
-
print("citations", citations)
|
425 |
-
|
426 |
-
return contexts, citations
|
427 |
|
428 |
|
429 |
def get_model_path(model: str, update_model: bool = False):
|
@@ -502,7 +483,6 @@ def generate_ollama_batch_embeddings(
|
|
502 |
r.raise_for_status()
|
503 |
data = r.json()
|
504 |
|
505 |
-
print(data)
|
506 |
if "embeddings" in data:
|
507 |
return data["embeddings"]
|
508 |
else:
|
|
|
307 |
return lambda query: generate_multiple(query, func)
|
308 |
|
309 |
|
310 |
+
def get_sources_from_files(
|
311 |
files,
|
312 |
queries,
|
313 |
embedding_function,
|
|
|
387 |
del file["data"]
|
388 |
relevant_contexts.append({**context, "file": file})
|
389 |
|
390 |
+
sources = []
|
|
|
391 |
for context in relevant_contexts:
|
392 |
try:
|
393 |
if "documents" in context:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
394 |
if "metadatas" in context:
|
395 |
+
source = {
|
396 |
"source": context["file"],
|
397 |
"document": context["documents"][0],
|
398 |
"metadata": context["metadatas"][0],
|
399 |
}
|
400 |
if "distances" in context and context["distances"]:
|
401 |
+
source["distances"] = context["distances"][0]
|
402 |
+
|
403 |
+
sources.append(source)
|
404 |
except Exception as e:
|
405 |
log.exception(e)
|
406 |
|
407 |
+
return sources
|
|
|
|
|
|
|
408 |
|
409 |
|
410 |
def get_model_path(model: str, update_model: bool = False):
|
|
|
483 |
r.raise_for_status()
|
484 |
data = r.json()
|
485 |
|
|
|
486 |
if "embeddings" in data:
|
487 |
return data["embeddings"]
|
488 |
else:
|
backend/open_webui/apps/retrieval/web/mojeek.py
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import logging
|
2 |
+
from typing import Optional
|
3 |
+
|
4 |
+
import requests
|
5 |
+
from open_webui.apps.retrieval.web.main import SearchResult, get_filtered_results
|
6 |
+
from open_webui.env import SRC_LOG_LEVELS
|
7 |
+
|
8 |
+
log = logging.getLogger(__name__)
|
9 |
+
log.setLevel(SRC_LOG_LEVELS["RAG"])
|
10 |
+
|
11 |
+
|
12 |
+
def search_mojeek(
|
13 |
+
api_key: str, query: str, count: int, filter_list: Optional[list[str]] = None
|
14 |
+
) -> list[SearchResult]:
|
15 |
+
"""Search using Mojeek's Search API and return the results as a list of SearchResult objects.
|
16 |
+
|
17 |
+
Args:
|
18 |
+
api_key (str): A Mojeek Search API key
|
19 |
+
query (str): The query to search for
|
20 |
+
"""
|
21 |
+
url = "https://api.mojeek.com/search"
|
22 |
+
headers = {
|
23 |
+
"Accept": "application/json",
|
24 |
+
}
|
25 |
+
params = {"q": query, "api_key": api_key, "fmt": "json", "t": count}
|
26 |
+
|
27 |
+
response = requests.get(url, headers=headers, params=params)
|
28 |
+
response.raise_for_status()
|
29 |
+
json_response = response.json()
|
30 |
+
results = json_response.get("response", {}).get("results", [])
|
31 |
+
print(results)
|
32 |
+
if filter_list:
|
33 |
+
results = get_filtered_results(results, filter_list)
|
34 |
+
|
35 |
+
return [
|
36 |
+
SearchResult(
|
37 |
+
link=result["url"], title=result.get("title"), snippet=result.get("desc")
|
38 |
+
)
|
39 |
+
for result in results
|
40 |
+
]
|
backend/open_webui/apps/webui/routers/auths.py
CHANGED
@@ -238,10 +238,20 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
|
|
238 |
|
239 |
user = Users.get_user_by_email(mail)
|
240 |
if not user:
|
241 |
-
|
242 |
try:
|
243 |
-
|
244 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
245 |
|
246 |
if not user:
|
247 |
raise HTTPException(
|
@@ -253,7 +263,7 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm):
|
|
253 |
except Exception as err:
|
254 |
raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
|
255 |
|
256 |
-
user = Auths.
|
257 |
|
258 |
if user:
|
259 |
token = create_token(
|
|
|
238 |
|
239 |
user = Users.get_user_by_email(mail)
|
240 |
if not user:
|
|
|
241 |
try:
|
242 |
+
role = (
|
243 |
+
"admin"
|
244 |
+
if Users.get_num_users() == 0
|
245 |
+
else request.app.state.config.DEFAULT_USER_ROLE
|
246 |
+
)
|
247 |
+
|
248 |
+
user = Auths.insert_new_auth(
|
249 |
+
mail,
|
250 |
+
str(uuid.uuid4()),
|
251 |
+
cn,
|
252 |
+
None,
|
253 |
+
role,
|
254 |
+
)
|
255 |
|
256 |
if not user:
|
257 |
raise HTTPException(
|
|
|
263 |
except Exception as err:
|
264 |
raise HTTPException(500, detail=ERROR_MESSAGES.DEFAULT(err))
|
265 |
|
266 |
+
user = Auths.authenticate_user_by_trusted_header(mail)
|
267 |
|
268 |
if user:
|
269 |
token = create_token(
|
backend/open_webui/apps/webui/routers/files.py
CHANGED
@@ -56,7 +56,7 @@ def upload_file(file: UploadFile = File(...), user=Depends(get_verified_user)):
|
|
56 |
FileForm(
|
57 |
**{
|
58 |
"id": id,
|
59 |
-
"filename":
|
60 |
"path": file_path,
|
61 |
"meta": {
|
62 |
"name": name,
|
|
|
56 |
FileForm(
|
57 |
**{
|
58 |
"id": id,
|
59 |
+
"filename": name,
|
60 |
"path": file_path,
|
61 |
"meta": {
|
62 |
"name": name,
|
backend/open_webui/apps/webui/routers/tools.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1 |
-
import os
|
2 |
from pathlib import Path
|
3 |
from typing import Optional
|
4 |
|
@@ -10,7 +9,7 @@ from open_webui.apps.webui.models.tools import (
|
|
10 |
Tools,
|
11 |
)
|
12 |
from open_webui.apps.webui.utils import load_tools_module_by_id, replace_imports
|
13 |
-
from open_webui.config import CACHE_DIR
|
14 |
from open_webui.constants import ERROR_MESSAGES
|
15 |
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
16 |
from open_webui.utils.tools import get_tools_specs
|
@@ -300,38 +299,35 @@ async def update_tools_valves_by_id(
|
|
300 |
request: Request, id: str, form_data: dict, user=Depends(get_verified_user)
|
301 |
):
|
302 |
tools = Tools.get_tool_by_id(id)
|
303 |
-
if tools:
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
if hasattr(tools_module, "Valves"):
|
311 |
-
Valves = tools_module.Valves
|
312 |
-
|
313 |
-
try:
|
314 |
-
form_data = {k: v for k, v in form_data.items() if v is not None}
|
315 |
-
valves = Valves(**form_data)
|
316 |
-
Tools.update_tool_valves_by_id(id, valves.model_dump())
|
317 |
-
return valves.model_dump()
|
318 |
-
except Exception as e:
|
319 |
-
print(e)
|
320 |
-
raise HTTPException(
|
321 |
-
status_code=status.HTTP_400_BAD_REQUEST,
|
322 |
-
detail=ERROR_MESSAGES.DEFAULT(str(e)),
|
323 |
-
)
|
324 |
-
else:
|
325 |
-
raise HTTPException(
|
326 |
-
status_code=status.HTTP_401_UNAUTHORIZED,
|
327 |
-
detail=ERROR_MESSAGES.NOT_FOUND,
|
328 |
-
)
|
329 |
-
|
330 |
else:
|
|
|
|
|
|
|
|
|
331 |
raise HTTPException(
|
332 |
status_code=status.HTTP_401_UNAUTHORIZED,
|
333 |
detail=ERROR_MESSAGES.NOT_FOUND,
|
334 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
|
336 |
|
337 |
############################
|
|
|
|
|
1 |
from pathlib import Path
|
2 |
from typing import Optional
|
3 |
|
|
|
9 |
Tools,
|
10 |
)
|
11 |
from open_webui.apps.webui.utils import load_tools_module_by_id, replace_imports
|
12 |
+
from open_webui.config import CACHE_DIR
|
13 |
from open_webui.constants import ERROR_MESSAGES
|
14 |
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
15 |
from open_webui.utils.tools import get_tools_specs
|
|
|
299 |
request: Request, id: str, form_data: dict, user=Depends(get_verified_user)
|
300 |
):
|
301 |
tools = Tools.get_tool_by_id(id)
|
302 |
+
if not tools:
|
303 |
+
raise HTTPException(
|
304 |
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
305 |
+
detail=ERROR_MESSAGES.NOT_FOUND,
|
306 |
+
)
|
307 |
+
if id in request.app.state.TOOLS:
|
308 |
+
tools_module = request.app.state.TOOLS[id]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
else:
|
310 |
+
tools_module, _ = load_tools_module_by_id(id)
|
311 |
+
request.app.state.TOOLS[id] = tools_module
|
312 |
+
|
313 |
+
if not hasattr(tools_module, "Valves"):
|
314 |
raise HTTPException(
|
315 |
status_code=status.HTTP_401_UNAUTHORIZED,
|
316 |
detail=ERROR_MESSAGES.NOT_FOUND,
|
317 |
)
|
318 |
+
Valves = tools_module.Valves
|
319 |
+
|
320 |
+
try:
|
321 |
+
form_data = {k: v for k, v in form_data.items() if v is not None}
|
322 |
+
valves = Valves(**form_data)
|
323 |
+
Tools.update_tool_valves_by_id(id, valves.model_dump())
|
324 |
+
return valves.model_dump()
|
325 |
+
except Exception as e:
|
326 |
+
print(e)
|
327 |
+
raise HTTPException(
|
328 |
+
status_code=status.HTTP_400_BAD_REQUEST,
|
329 |
+
detail=ERROR_MESSAGES.DEFAULT(str(e)),
|
330 |
+
)
|
331 |
|
332 |
|
333 |
############################
|
backend/open_webui/config.py
CHANGED
@@ -1181,21 +1181,32 @@ CHUNK_OVERLAP = PersistentConfig(
|
|
1181 |
int(os.environ.get("CHUNK_OVERLAP", "100")),
|
1182 |
)
|
1183 |
|
1184 |
-
DEFAULT_RAG_TEMPLATE = """
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1185 |
|
1186 |
<context>
|
1187 |
{{CONTEXT}}
|
1188 |
</context>
|
1189 |
|
1190 |
-
<rules>
|
1191 |
-
- If you don't know, just say so.
|
1192 |
-
- If you are not sure, ask for clarification.
|
1193 |
-
- Answer in the same language as the user query.
|
1194 |
-
- If the context appears unreadable or of poor quality, tell the user then answer as best as you can.
|
1195 |
-
- If the answer is not in the context but you think you know the answer, explain that to the user then answer with your own knowledge.
|
1196 |
-
- Answer directly and without using xml tags.
|
1197 |
-
</rules>
|
1198 |
-
|
1199 |
<user_query>
|
1200 |
{{QUERY}}
|
1201 |
</user_query>
|
@@ -1290,6 +1301,12 @@ BRAVE_SEARCH_API_KEY = PersistentConfig(
|
|
1290 |
os.getenv("BRAVE_SEARCH_API_KEY", ""),
|
1291 |
)
|
1292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1293 |
SERPSTACK_API_KEY = PersistentConfig(
|
1294 |
"SERPSTACK_API_KEY",
|
1295 |
"rag.web.search.serpstack_api_key",
|
|
|
1181 |
int(os.environ.get("CHUNK_OVERLAP", "100")),
|
1182 |
)
|
1183 |
|
1184 |
+
DEFAULT_RAG_TEMPLATE = """### Task:
|
1185 |
+
Respond to the user query using the provided context, incorporating inline citations in the format [source_id] **only when the <source_id> tag is explicitly provided** in the context.
|
1186 |
+
|
1187 |
+
### Guidelines:
|
1188 |
+
- If you don't know the answer, clearly state that.
|
1189 |
+
- If uncertain, ask the user for clarification.
|
1190 |
+
- Respond in the same language as the user's query.
|
1191 |
+
- If the context is unreadable or of poor quality, inform the user and provide the best possible answer.
|
1192 |
+
- If the answer isn't present in the context but you possess the knowledge, explain this to the user and provide the answer using your own understanding.
|
1193 |
+
- **Only include inline citations using [source_id] when a <source_id> tag is explicitly provided in the context.**
|
1194 |
+
- Do not cite if the <source_id> tag is not provided in the context.
|
1195 |
+
- Do not use XML tags in your response.
|
1196 |
+
- Ensure citations are concise and directly related to the information provided.
|
1197 |
+
|
1198 |
+
### Example of Citation:
|
1199 |
+
If the user asks about a specific topic and the information is found in "whitepaper.pdf" with a provided <source_id>, the response should include the citation like so:
|
1200 |
+
* "According to the study, the proposed method increases efficiency by 20% [whitepaper.pdf]."
|
1201 |
+
If no <source_id> is present, the response should omit the citation.
|
1202 |
+
|
1203 |
+
### Output:
|
1204 |
+
Provide a clear and direct response to the user's query, including inline citations in the format [source_id] only when the <source_id> tag is present in the context.
|
1205 |
|
1206 |
<context>
|
1207 |
{{CONTEXT}}
|
1208 |
</context>
|
1209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1210 |
<user_query>
|
1211 |
{{QUERY}}
|
1212 |
</user_query>
|
|
|
1301 |
os.getenv("BRAVE_SEARCH_API_KEY", ""),
|
1302 |
)
|
1303 |
|
1304 |
+
MOJEEK_SEARCH_API_KEY = PersistentConfig(
|
1305 |
+
"MOJEEK_SEARCH_API_KEY",
|
1306 |
+
"rag.web.search.mojeek_search_api_key",
|
1307 |
+
os.getenv("MOJEEK_SEARCH_API_KEY", ""),
|
1308 |
+
)
|
1309 |
+
|
1310 |
SERPSTACK_API_KEY = PersistentConfig(
|
1311 |
"SERPSTACK_API_KEY",
|
1312 |
"rag.web.search.serpstack_api_key",
|
backend/open_webui/main.py
CHANGED
@@ -49,7 +49,7 @@ from open_webui.apps.openai.main import (
|
|
49 |
get_all_models_responses as get_openai_models_responses,
|
50 |
)
|
51 |
from open_webui.apps.retrieval.main import app as retrieval_app
|
52 |
-
from open_webui.apps.retrieval.utils import
|
53 |
from open_webui.apps.socket.main import (
|
54 |
app as socket_app,
|
55 |
periodic_usage_pool_cleanup,
|
@@ -380,8 +380,7 @@ async def chat_completion_tools_handler(
|
|
380 |
return body, {}
|
381 |
|
382 |
skip_files = False
|
383 |
-
|
384 |
-
citations = []
|
385 |
|
386 |
task_model_id = get_task_model_id(
|
387 |
body["model"],
|
@@ -463,21 +462,39 @@ async def chat_completion_tools_handler(
|
|
463 |
except Exception as e:
|
464 |
tool_output = str(e)
|
465 |
|
466 |
-
|
467 |
-
citations.append(
|
468 |
-
{
|
469 |
-
"source": {
|
470 |
-
"name": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
|
471 |
-
},
|
472 |
-
"document": [tool_output],
|
473 |
-
"metadata": [{"source": tool_function_name}],
|
474 |
-
}
|
475 |
-
)
|
476 |
-
if tools[tool_function_name]["file_handler"]:
|
477 |
-
skip_files = True
|
478 |
|
479 |
if isinstance(tool_output, str):
|
480 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
481 |
except Exception as e:
|
482 |
log.exception(f"Error: {e}")
|
483 |
content = None
|
@@ -485,19 +502,18 @@ async def chat_completion_tools_handler(
|
|
485 |
log.exception(f"Error: {e}")
|
486 |
content = None
|
487 |
|
488 |
-
log.debug(f"tool_contexts: {
|
489 |
|
490 |
if skip_files and "files" in body.get("metadata", {}):
|
491 |
del body["metadata"]["files"]
|
492 |
|
493 |
-
return body, {"
|
494 |
|
495 |
|
496 |
async def chat_completion_files_handler(
|
497 |
body: dict, user: UserModel
|
498 |
) -> tuple[dict, dict[str, list]]:
|
499 |
-
|
500 |
-
citations = []
|
501 |
|
502 |
try:
|
503 |
queries_response = await generate_queries(
|
@@ -525,7 +541,7 @@ async def chat_completion_files_handler(
|
|
525 |
print(f"{queries=}")
|
526 |
|
527 |
if files := body.get("metadata", {}).get("files", None):
|
528 |
-
|
529 |
files=files,
|
530 |
queries=queries,
|
531 |
embedding_function=retrieval_app.state.EMBEDDING_FUNCTION,
|
@@ -535,9 +551,8 @@ async def chat_completion_files_handler(
|
|
535 |
hybrid_search=retrieval_app.state.config.ENABLE_RAG_HYBRID_SEARCH,
|
536 |
)
|
537 |
|
538 |
-
log.debug(f"rag_contexts:
|
539 |
-
|
540 |
-
return body, {"contexts": contexts, "citations": citations}
|
541 |
|
542 |
|
543 |
def is_chat_completion_request(request):
|
@@ -638,8 +653,7 @@ class ChatCompletionMiddleware(BaseHTTPMiddleware):
|
|
638 |
# Initialize data_items to store additional data to be sent to the client
|
639 |
# Initialize contexts and citation
|
640 |
data_items = []
|
641 |
-
|
642 |
-
citations = []
|
643 |
|
644 |
try:
|
645 |
body, flags = await chat_completion_filter_functions_handler(
|
@@ -665,21 +679,36 @@ class ChatCompletionMiddleware(BaseHTTPMiddleware):
|
|
665 |
body, flags = await chat_completion_tools_handler(
|
666 |
body, user, models, extra_params
|
667 |
)
|
668 |
-
|
669 |
-
citations.extend(flags.get("citations", []))
|
670 |
except Exception as e:
|
671 |
log.exception(e)
|
672 |
|
673 |
try:
|
674 |
body, flags = await chat_completion_files_handler(body, user)
|
675 |
-
|
676 |
-
citations.extend(flags.get("citations", []))
|
677 |
except Exception as e:
|
678 |
log.exception(e)
|
679 |
|
680 |
# If context is not empty, insert it into the messages
|
681 |
-
if len(
|
682 |
-
context_string = "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
683 |
prompt = get_last_user_message(body["messages"])
|
684 |
|
685 |
if prompt is None:
|
@@ -710,8 +739,11 @@ class ChatCompletionMiddleware(BaseHTTPMiddleware):
|
|
710 |
)
|
711 |
|
712 |
# If there are citations, add them to the data_items
|
713 |
-
|
714 |
-
|
|
|
|
|
|
|
715 |
|
716 |
modified_body_bytes = json.dumps(body).encode("utf-8")
|
717 |
# Replace the request body with the modified one
|
@@ -1020,7 +1052,7 @@ async def get_all_base_models():
|
|
1020 |
return models
|
1021 |
|
1022 |
|
1023 |
-
@cached(ttl=
|
1024 |
async def get_all_models():
|
1025 |
models = await get_all_base_models()
|
1026 |
|
@@ -1313,7 +1345,6 @@ async def generate_chat_completions(
|
|
1313 |
|
1314 |
@app.post("/api/chat/completed")
|
1315 |
async def chat_completed(form_data: dict, user=Depends(get_verified_user)):
|
1316 |
-
|
1317 |
model_list = await get_all_models()
|
1318 |
models = {model["id"]: model for model in model_list}
|
1319 |
|
|
|
49 |
get_all_models_responses as get_openai_models_responses,
|
50 |
)
|
51 |
from open_webui.apps.retrieval.main import app as retrieval_app
|
52 |
+
from open_webui.apps.retrieval.utils import get_sources_from_files, rag_template
|
53 |
from open_webui.apps.socket.main import (
|
54 |
app as socket_app,
|
55 |
periodic_usage_pool_cleanup,
|
|
|
380 |
return body, {}
|
381 |
|
382 |
skip_files = False
|
383 |
+
sources = []
|
|
|
384 |
|
385 |
task_model_id = get_task_model_id(
|
386 |
body["model"],
|
|
|
462 |
except Exception as e:
|
463 |
tool_output = str(e)
|
464 |
|
465 |
+
print(tools[tool_function_name]["citation"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
466 |
|
467 |
if isinstance(tool_output, str):
|
468 |
+
if tools[tool_function_name]["citation"]:
|
469 |
+
sources.append(
|
470 |
+
{
|
471 |
+
"source": {
|
472 |
+
"name": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
|
473 |
+
},
|
474 |
+
"document": [tool_output],
|
475 |
+
"metadata": [
|
476 |
+
{
|
477 |
+
"source": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
|
478 |
+
}
|
479 |
+
],
|
480 |
+
}
|
481 |
+
)
|
482 |
+
else:
|
483 |
+
sources.append(
|
484 |
+
{
|
485 |
+
"source": {},
|
486 |
+
"document": [tool_output],
|
487 |
+
"metadata": [
|
488 |
+
{
|
489 |
+
"source": f"TOOL:{tools[tool_function_name]['toolkit_id']}/{tool_function_name}"
|
490 |
+
}
|
491 |
+
],
|
492 |
+
}
|
493 |
+
)
|
494 |
+
|
495 |
+
if tools[tool_function_name]["file_handler"]:
|
496 |
+
skip_files = True
|
497 |
+
|
498 |
except Exception as e:
|
499 |
log.exception(f"Error: {e}")
|
500 |
content = None
|
|
|
502 |
log.exception(f"Error: {e}")
|
503 |
content = None
|
504 |
|
505 |
+
log.debug(f"tool_contexts: {sources}")
|
506 |
|
507 |
if skip_files and "files" in body.get("metadata", {}):
|
508 |
del body["metadata"]["files"]
|
509 |
|
510 |
+
return body, {"sources": sources}
|
511 |
|
512 |
|
513 |
async def chat_completion_files_handler(
|
514 |
body: dict, user: UserModel
|
515 |
) -> tuple[dict, dict[str, list]]:
|
516 |
+
sources = []
|
|
|
517 |
|
518 |
try:
|
519 |
queries_response = await generate_queries(
|
|
|
541 |
print(f"{queries=}")
|
542 |
|
543 |
if files := body.get("metadata", {}).get("files", None):
|
544 |
+
sources = get_sources_from_files(
|
545 |
files=files,
|
546 |
queries=queries,
|
547 |
embedding_function=retrieval_app.state.EMBEDDING_FUNCTION,
|
|
|
551 |
hybrid_search=retrieval_app.state.config.ENABLE_RAG_HYBRID_SEARCH,
|
552 |
)
|
553 |
|
554 |
+
log.debug(f"rag_contexts:sources: {sources}")
|
555 |
+
return body, {"sources": sources}
|
|
|
556 |
|
557 |
|
558 |
def is_chat_completion_request(request):
|
|
|
653 |
# Initialize data_items to store additional data to be sent to the client
|
654 |
# Initialize contexts and citation
|
655 |
data_items = []
|
656 |
+
sources = []
|
|
|
657 |
|
658 |
try:
|
659 |
body, flags = await chat_completion_filter_functions_handler(
|
|
|
679 |
body, flags = await chat_completion_tools_handler(
|
680 |
body, user, models, extra_params
|
681 |
)
|
682 |
+
sources.extend(flags.get("sources", []))
|
|
|
683 |
except Exception as e:
|
684 |
log.exception(e)
|
685 |
|
686 |
try:
|
687 |
body, flags = await chat_completion_files_handler(body, user)
|
688 |
+
sources.extend(flags.get("sources", []))
|
|
|
689 |
except Exception as e:
|
690 |
log.exception(e)
|
691 |
|
692 |
# If context is not empty, insert it into the messages
|
693 |
+
if len(sources) > 0:
|
694 |
+
context_string = ""
|
695 |
+
for source_idx, source in enumerate(sources):
|
696 |
+
source_id = source.get("source", {}).get("name", "")
|
697 |
+
|
698 |
+
if "document" in source:
|
699 |
+
for doc_idx, doc_context in enumerate(source["document"]):
|
700 |
+
metadata = source.get("metadata")
|
701 |
+
|
702 |
+
if metadata:
|
703 |
+
doc_source_id = metadata[doc_idx].get("source", source_id)
|
704 |
+
|
705 |
+
if source_id:
|
706 |
+
context_string += f"<source><source_id>{doc_source_id}</source_id><source_context>{doc_context}</source_context></source>\n"
|
707 |
+
else:
|
708 |
+
# If there is no source_id, then do not include the source_id tag
|
709 |
+
context_string += f"<source><source_context>{doc_context}</source_context></source>\n"
|
710 |
+
|
711 |
+
context_string = context_string.strip()
|
712 |
prompt = get_last_user_message(body["messages"])
|
713 |
|
714 |
if prompt is None:
|
|
|
739 |
)
|
740 |
|
741 |
# If there are citations, add them to the data_items
|
742 |
+
sources = [
|
743 |
+
source for source in sources if source.get("source", {}).get("name", "")
|
744 |
+
]
|
745 |
+
if len(sources) > 0:
|
746 |
+
data_items.append({"sources": sources})
|
747 |
|
748 |
modified_body_bytes = json.dumps(body).encode("utf-8")
|
749 |
# Replace the request body with the modified one
|
|
|
1052 |
return models
|
1053 |
|
1054 |
|
1055 |
+
@cached(ttl=3)
|
1056 |
async def get_all_models():
|
1057 |
models = await get_all_base_models()
|
1058 |
|
|
|
1345 |
|
1346 |
@app.post("/api/chat/completed")
|
1347 |
async def chat_completed(form_data: dict, user=Depends(get_verified_user)):
|
|
|
1348 |
model_list = await get_all_models()
|
1349 |
models = {model["id"]: model for model in model_list}
|
1350 |
|
backend/open_webui/utils/tools.py
CHANGED
@@ -1,11 +1,14 @@
|
|
1 |
import inspect
|
2 |
import logging
|
3 |
-
|
|
|
|
|
4 |
|
|
|
5 |
from open_webui.apps.webui.models.tools import Tools
|
6 |
from open_webui.apps.webui.models.users import UserModel
|
7 |
from open_webui.apps.webui.utils import load_tools_module_by_id
|
8 |
-
from
|
9 |
|
10 |
log = logging.getLogger(__name__)
|
11 |
|
@@ -14,17 +17,16 @@ def apply_extra_params_to_tool_function(
|
|
14 |
function: Callable, extra_params: dict
|
15 |
) -> Callable[..., Awaitable]:
|
16 |
sig = inspect.signature(function)
|
17 |
-
extra_params = {
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
21 |
|
22 |
-
async def new_function(**kwargs):
|
23 |
-
|
24 |
-
if is_coroutine:
|
25 |
-
return await function(**extra_kwargs)
|
26 |
-
return function(**extra_kwargs)
|
27 |
|
|
|
28 |
return new_function
|
29 |
|
30 |
|
@@ -55,11 +57,6 @@ def get_tools(
|
|
55 |
)
|
56 |
|
57 |
for spec in tools.specs:
|
58 |
-
# TODO: Fix hack for OpenAI API
|
59 |
-
for val in spec.get("parameters", {}).get("properties", {}).values():
|
60 |
-
if val["type"] == "str":
|
61 |
-
val["type"] = "string"
|
62 |
-
|
63 |
# Remove internal parameters
|
64 |
spec["parameters"]["properties"] = {
|
65 |
key: val
|
@@ -72,15 +69,12 @@ def get_tools(
|
|
72 |
# convert to function that takes only model params and inserts custom params
|
73 |
original_func = getattr(module, function_name)
|
74 |
callable = apply_extra_params_to_tool_function(original_func, extra_params)
|
75 |
-
if hasattr(original_func, "__doc__"):
|
76 |
-
callable.__doc__ = original_func.__doc__
|
77 |
-
|
78 |
# TODO: This needs to be a pydantic model
|
79 |
tool_dict = {
|
80 |
"toolkit_id": tool_id,
|
81 |
"callable": callable,
|
82 |
"spec": spec,
|
83 |
-
"pydantic_model":
|
84 |
"file_handler": hasattr(module, "file_handler") and module.file_handler,
|
85 |
"citation": hasattr(module, "citation") and module.citation,
|
86 |
}
|
@@ -96,78 +90,75 @@ def get_tools(
|
|
96 |
return tools_dict
|
97 |
|
98 |
|
99 |
-
def
|
100 |
-
|
101 |
-
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
param_dict[param.strip()] = desc.strip()
|
109 |
-
ret_dict = {"description": description, "params": param_dict}
|
110 |
-
return ret_dict
|
111 |
|
|
|
|
|
|
|
112 |
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
and not func.startswith("__")
|
119 |
-
and not inspect.isclass(getattr(
|
120 |
]
|
121 |
|
122 |
-
specs = []
|
123 |
-
for function_item in function_list:
|
124 |
-
function_name = function_item["name"]
|
125 |
-
function = function_item["function"]
|
126 |
-
|
127 |
-
function_doc = doc_to_dict(function.__doc__ or function_name)
|
128 |
-
specs.append(
|
129 |
-
{
|
130 |
-
"name": function_name,
|
131 |
-
# TODO: multi-line desc?
|
132 |
-
"description": function_doc.get("description", function_name),
|
133 |
-
"parameters": {
|
134 |
-
"type": "object",
|
135 |
-
"properties": {
|
136 |
-
param_name: {
|
137 |
-
"type": param_annotation.__name__.lower(),
|
138 |
-
**(
|
139 |
-
{
|
140 |
-
"enum": (
|
141 |
-
str(param_annotation.__args__)
|
142 |
-
if hasattr(param_annotation, "__args__")
|
143 |
-
else None
|
144 |
-
)
|
145 |
-
}
|
146 |
-
if hasattr(param_annotation, "__args__")
|
147 |
-
else {}
|
148 |
-
),
|
149 |
-
"description": function_doc.get("params", {}).get(
|
150 |
-
param_name, param_name
|
151 |
-
),
|
152 |
-
}
|
153 |
-
for param_name, param_annotation in get_type_hints(
|
154 |
-
function
|
155 |
-
).items()
|
156 |
-
if param_name != "return"
|
157 |
-
and not (
|
158 |
-
param_name.startswith("__") and param_name.endswith("__")
|
159 |
-
)
|
160 |
-
},
|
161 |
-
"required": [
|
162 |
-
name
|
163 |
-
for name, param in inspect.signature(
|
164 |
-
function
|
165 |
-
).parameters.items()
|
166 |
-
if param.default is param.empty
|
167 |
-
and not (name.startswith("__") and name.endswith("__"))
|
168 |
-
],
|
169 |
-
},
|
170 |
-
}
|
171 |
-
)
|
172 |
|
173 |
-
|
|
|
|
|
|
|
|
1 |
import inspect
|
2 |
import logging
|
3 |
+
import re
|
4 |
+
from typing import Any, Awaitable, Callable, get_type_hints
|
5 |
+
from functools import update_wrapper, partial
|
6 |
|
7 |
+
from langchain_core.utils.function_calling import convert_to_openai_function
|
8 |
from open_webui.apps.webui.models.tools import Tools
|
9 |
from open_webui.apps.webui.models.users import UserModel
|
10 |
from open_webui.apps.webui.utils import load_tools_module_by_id
|
11 |
+
from pydantic import BaseModel, Field, create_model
|
12 |
|
13 |
log = logging.getLogger(__name__)
|
14 |
|
|
|
17 |
function: Callable, extra_params: dict
|
18 |
) -> Callable[..., Awaitable]:
|
19 |
sig = inspect.signature(function)
|
20 |
+
extra_params = {k: v for k, v in extra_params.items() if k in sig.parameters}
|
21 |
+
partial_func = partial(function, **extra_params)
|
22 |
+
if inspect.iscoroutinefunction(function):
|
23 |
+
update_wrapper(partial_func, function)
|
24 |
+
return partial_func
|
25 |
|
26 |
+
async def new_function(*args, **kwargs):
|
27 |
+
return partial_func(*args, **kwargs)
|
|
|
|
|
|
|
28 |
|
29 |
+
update_wrapper(new_function, function)
|
30 |
return new_function
|
31 |
|
32 |
|
|
|
57 |
)
|
58 |
|
59 |
for spec in tools.specs:
|
|
|
|
|
|
|
|
|
|
|
60 |
# Remove internal parameters
|
61 |
spec["parameters"]["properties"] = {
|
62 |
key: val
|
|
|
69 |
# convert to function that takes only model params and inserts custom params
|
70 |
original_func = getattr(module, function_name)
|
71 |
callable = apply_extra_params_to_tool_function(original_func, extra_params)
|
|
|
|
|
|
|
72 |
# TODO: This needs to be a pydantic model
|
73 |
tool_dict = {
|
74 |
"toolkit_id": tool_id,
|
75 |
"callable": callable,
|
76 |
"spec": spec,
|
77 |
+
"pydantic_model": function_to_pydantic_model(callable),
|
78 |
"file_handler": hasattr(module, "file_handler") and module.file_handler,
|
79 |
"citation": hasattr(module, "citation") and module.citation,
|
80 |
}
|
|
|
90 |
return tools_dict
|
91 |
|
92 |
|
93 |
+
def parse_docstring(docstring):
|
94 |
+
"""
|
95 |
+
Parse a function's docstring to extract parameter descriptions in reST format.
|
96 |
+
|
97 |
+
Args:
|
98 |
+
docstring (str): The docstring to parse.
|
99 |
+
|
100 |
+
Returns:
|
101 |
+
dict: A dictionary where keys are parameter names and values are descriptions.
|
102 |
+
"""
|
103 |
+
if not docstring:
|
104 |
+
return {}
|
105 |
+
|
106 |
+
# Regex to match `:param name: description` format
|
107 |
+
param_pattern = re.compile(r":param (\w+):\s*(.+)")
|
108 |
+
param_descriptions = {}
|
109 |
+
|
110 |
+
for line in docstring.splitlines():
|
111 |
+
match = param_pattern.match(line.strip())
|
112 |
+
if match:
|
113 |
+
param_name, param_description = match.groups()
|
114 |
+
param_descriptions[param_name] = param_description
|
115 |
+
|
116 |
+
return param_descriptions
|
117 |
+
|
118 |
|
119 |
+
def function_to_pydantic_model(func: Callable) -> type[BaseModel]:
|
120 |
+
"""
|
121 |
+
Converts a Python function's type hints and docstring to a Pydantic model,
|
122 |
+
including support for nested types, default values, and descriptions.
|
|
|
|
|
|
|
123 |
|
124 |
+
Args:
|
125 |
+
func: The function whose type hints and docstring should be converted.
|
126 |
+
model_name: The name of the generated Pydantic model.
|
127 |
|
128 |
+
Returns:
|
129 |
+
A Pydantic model class.
|
130 |
+
"""
|
131 |
+
type_hints = get_type_hints(func)
|
132 |
+
signature = inspect.signature(func)
|
133 |
+
parameters = signature.parameters
|
134 |
+
|
135 |
+
docstring = func.__doc__
|
136 |
+
descriptions = parse_docstring(docstring)
|
137 |
+
|
138 |
+
field_defs = {}
|
139 |
+
for name, param in parameters.items():
|
140 |
+
type_hint = type_hints.get(name, Any)
|
141 |
+
default_value = param.default if param.default is not param.empty else ...
|
142 |
+
description = descriptions.get(name, None)
|
143 |
+
if not description:
|
144 |
+
field_defs[name] = type_hint, default_value
|
145 |
+
continue
|
146 |
+
field_defs[name] = type_hint, Field(default_value, description=description)
|
147 |
+
|
148 |
+
return create_model(func.__name__, **field_defs)
|
149 |
+
|
150 |
+
|
151 |
+
def get_callable_attributes(tool: object) -> list[Callable]:
|
152 |
+
return [
|
153 |
+
getattr(tool, func)
|
154 |
+
for func in dir(tool)
|
155 |
+
if callable(getattr(tool, func))
|
156 |
and not func.startswith("__")
|
157 |
+
and not inspect.isclass(getattr(tool, func))
|
158 |
]
|
159 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
160 |
|
161 |
+
def get_tools_specs(tool_class: object) -> list[dict]:
|
162 |
+
function_list = get_callable_attributes(tool_class)
|
163 |
+
models = map(function_to_pydantic_model, function_list)
|
164 |
+
return [convert_to_openai_function(tool) for tool in models]
|
package-lock.json
CHANGED
@@ -1,12 +1,12 @@
|
|
1 |
{
|
2 |
"name": "open-webui",
|
3 |
-
"version": "0.4.
|
4 |
"lockfileVersion": 3,
|
5 |
"requires": true,
|
6 |
"packages": {
|
7 |
"": {
|
8 |
"name": "open-webui",
|
9 |
-
"version": "0.4.
|
10 |
"dependencies": {
|
11 |
"@codemirror/lang-javascript": "^6.2.2",
|
12 |
"@codemirror/lang-python": "^6.1.6",
|
@@ -16,6 +16,13 @@
|
|
16 |
"@mediapipe/tasks-vision": "^0.10.17",
|
17 |
"@pyscript/core": "^0.4.32",
|
18 |
"@sveltejs/adapter-node": "^2.0.0",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
"@xyflow/svelte": "^0.1.19",
|
20 |
"async": "^3.2.5",
|
21 |
"bits-ui": "^0.19.7",
|
@@ -73,6 +80,7 @@
|
|
73 |
"postcss": "^8.4.31",
|
74 |
"prettier": "^3.3.3",
|
75 |
"prettier-plugin-svelte": "^3.2.6",
|
|
|
76 |
"svelte": "^4.2.18",
|
77 |
"svelte-check": "^3.8.5",
|
78 |
"svelte-confetti": "^1.3.2",
|
@@ -136,6 +144,13 @@
|
|
136 |
"resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz",
|
137 |
"integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A=="
|
138 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
"node_modules/@codemirror/autocomplete": {
|
140 |
"version": "6.16.2",
|
141 |
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.16.2.tgz",
|
@@ -1901,6 +1916,12 @@
|
|
1901 |
"type-checked-collections": "^0.1.7"
|
1902 |
}
|
1903 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
1904 |
"node_modules/@rollup/plugin-commonjs": {
|
1905 |
"version": "25.0.7",
|
1906 |
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz",
|
@@ -2326,6 +2347,391 @@
|
|
2326 |
"tailwindcss": ">=3.0.0 || insiders"
|
2327 |
}
|
2328 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2329 |
"node_modules/@types/cookie": {
|
2330 |
"version": "0.6.0",
|
2331 |
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
@@ -2405,6 +2811,16 @@
|
|
2405 |
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
2406 |
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
2407 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2408 |
"node_modules/@types/json-schema": {
|
2409 |
"version": "7.0.15",
|
2410 |
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
@@ -3425,6 +3841,13 @@
|
|
3425 |
"ieee754": "^1.2.1"
|
3426 |
}
|
3427 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3428 |
"node_modules/buffer-crc32": {
|
3429 |
"version": "0.2.13",
|
3430 |
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
@@ -3898,6 +4321,13 @@
|
|
3898 |
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
|
3899 |
"dev": true
|
3900 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3901 |
"node_modules/colors": {
|
3902 |
"version": "1.4.0",
|
3903 |
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
|
@@ -4760,6 +5190,20 @@
|
|
4760 |
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz",
|
4761 |
"integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="
|
4762 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4763 |
"node_modules/didyoumean": {
|
4764 |
"version": "1.2.2",
|
4765 |
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
@@ -5047,7 +5491,6 @@
|
|
5047 |
"version": "4.0.0",
|
5048 |
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
5049 |
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
5050 |
-
"dev": true,
|
5051 |
"engines": {
|
5052 |
"node": ">=10"
|
5053 |
},
|
@@ -5978,7 +6421,7 @@
|
|
5978 |
"version": "4.0.0",
|
5979 |
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
5980 |
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
5981 |
-
"
|
5982 |
"engines": {
|
5983 |
"node": ">=8"
|
5984 |
}
|
@@ -6241,6 +6684,13 @@
|
|
6241 |
"node": ">= 4"
|
6242 |
}
|
6243 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6244 |
"node_modules/import-fresh": {
|
6245 |
"version": "3.3.0",
|
6246 |
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
@@ -6982,6 +7432,22 @@
|
|
6982 |
"get-func-name": "^2.0.1"
|
6983 |
}
|
6984 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6985 |
"node_modules/magic-string": {
|
6986 |
"version": "0.30.11",
|
6987 |
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
|
@@ -8604,17 +9070,36 @@
|
|
8604 |
"node": "10.* || >= 12.*"
|
8605 |
}
|
8606 |
},
|
8607 |
-
"node_modules/prosemirror-
|
8608 |
-
"version": "
|
8609 |
-
"resolved": "https://registry.npmjs.org/prosemirror-
|
8610 |
-
"integrity": "sha512-
|
|
|
8611 |
"dependencies": {
|
8612 |
-
"prosemirror-model": "^1.0.0",
|
8613 |
-
"prosemirror-state": "^1.0.0",
|
8614 |
"prosemirror-transform": "^1.0.0"
|
8615 |
}
|
8616 |
},
|
8617 |
-
"node_modules/prosemirror-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8618 |
"version": "1.8.1",
|
8619 |
"resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz",
|
8620 |
"integrity": "sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==",
|
@@ -8737,18 +9222,48 @@
|
|
8737 |
"prosemirror-view": "^1.27.0"
|
8738 |
}
|
8739 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8740 |
"node_modules/prosemirror-transform": {
|
8741 |
-
"version": "1.10.
|
8742 |
-
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.
|
8743 |
-
"integrity": "sha512-
|
|
|
8744 |
"dependencies": {
|
8745 |
"prosemirror-model": "^1.21.0"
|
8746 |
}
|
8747 |
},
|
8748 |
"node_modules/prosemirror-view": {
|
8749 |
-
"version": "1.
|
8750 |
-
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.
|
8751 |
-
"integrity": "sha512-
|
|
|
8752 |
"dependencies": {
|
8753 |
"prosemirror-model": "^1.20.0",
|
8754 |
"prosemirror-state": "^1.0.0",
|
@@ -9236,7 +9751,7 @@
|
|
9236 |
"version": "7.8.1",
|
9237 |
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
|
9238 |
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
|
9239 |
-
"
|
9240 |
"dependencies": {
|
9241 |
"tslib": "^2.1.0"
|
9242 |
}
|
@@ -9329,6 +9844,387 @@
|
|
9329 |
"rimraf": "bin.js"
|
9330 |
}
|
9331 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9332 |
"node_modules/semver": {
|
9333 |
"version": "7.6.3",
|
9334 |
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
@@ -10044,6 +10940,29 @@
|
|
10044 |
"integrity": "sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA==",
|
10045 |
"dev": true
|
10046 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10047 |
"node_modules/tabbable": {
|
10048 |
"version": "6.2.0",
|
10049 |
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
|
@@ -10416,6 +11335,7 @@
|
|
10416 |
"version": "7.2.0",
|
10417 |
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz",
|
10418 |
"integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==",
|
|
|
10419 |
"dependencies": {
|
10420 |
"@mixmark-io/domino": "^2.2.0"
|
10421 |
}
|
@@ -10629,6 +11549,13 @@
|
|
10629 |
"node": ">= 10.13.0"
|
10630 |
}
|
10631 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10632 |
"node_modules/verror": {
|
10633 |
"version": "1.10.0",
|
10634 |
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
|
|
1 |
{
|
2 |
"name": "open-webui",
|
3 |
+
"version": "0.4.3",
|
4 |
"lockfileVersion": 3,
|
5 |
"requires": true,
|
6 |
"packages": {
|
7 |
"": {
|
8 |
"name": "open-webui",
|
9 |
+
"version": "0.4.3",
|
10 |
"dependencies": {
|
11 |
"@codemirror/lang-javascript": "^6.2.2",
|
12 |
"@codemirror/lang-python": "^6.1.6",
|
|
|
16 |
"@mediapipe/tasks-vision": "^0.10.17",
|
17 |
"@pyscript/core": "^0.4.32",
|
18 |
"@sveltejs/adapter-node": "^2.0.0",
|
19 |
+
"@tiptap/core": "^2.10.0",
|
20 |
+
"@tiptap/extension-code-block-lowlight": "^2.10.0",
|
21 |
+
"@tiptap/extension-highlight": "^2.10.0",
|
22 |
+
"@tiptap/extension-placeholder": "^2.10.0",
|
23 |
+
"@tiptap/extension-typography": "^2.10.0",
|
24 |
+
"@tiptap/pm": "^2.10.0",
|
25 |
+
"@tiptap/starter-kit": "^2.10.0",
|
26 |
"@xyflow/svelte": "^0.1.19",
|
27 |
"async": "^3.2.5",
|
28 |
"bits-ui": "^0.19.7",
|
|
|
80 |
"postcss": "^8.4.31",
|
81 |
"prettier": "^3.3.3",
|
82 |
"prettier-plugin-svelte": "^3.2.6",
|
83 |
+
"sass-embedded": "^1.81.0",
|
84 |
"svelte": "^4.2.18",
|
85 |
"svelte-check": "^3.8.5",
|
86 |
"svelte-confetti": "^1.3.2",
|
|
|
144 |
"resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz",
|
145 |
"integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A=="
|
146 |
},
|
147 |
+
"node_modules/@bufbuild/protobuf": {
|
148 |
+
"version": "2.2.2",
|
149 |
+
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.2.tgz",
|
150 |
+
"integrity": "sha512-UNtPCbrwrenpmrXuRwn9jYpPoweNXj8X5sMvYgsqYyaH8jQ6LfUJSk3dJLnBK+6sfYPrF4iAIo5sd5HQ+tg75A==",
|
151 |
+
"devOptional": true,
|
152 |
+
"license": "(Apache-2.0 AND BSD-3-Clause)"
|
153 |
+
},
|
154 |
"node_modules/@codemirror/autocomplete": {
|
155 |
"version": "6.16.2",
|
156 |
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.16.2.tgz",
|
|
|
1916 |
"type-checked-collections": "^0.1.7"
|
1917 |
}
|
1918 |
},
|
1919 |
+
"node_modules/@remirror/core-constants": {
|
1920 |
+
"version": "3.0.0",
|
1921 |
+
"resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz",
|
1922 |
+
"integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==",
|
1923 |
+
"license": "MIT"
|
1924 |
+
},
|
1925 |
"node_modules/@rollup/plugin-commonjs": {
|
1926 |
"version": "25.0.7",
|
1927 |
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz",
|
|
|
2347 |
"tailwindcss": ">=3.0.0 || insiders"
|
2348 |
}
|
2349 |
},
|
2350 |
+
"node_modules/@tiptap/core": {
|
2351 |
+
"version": "2.10.0",
|
2352 |
+
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.10.0.tgz",
|
2353 |
+
"integrity": "sha512-58nAjPxLRFcXepdDqQRC1mhrw6E8Sanqr6bbO4Tz0+FWgDJMZvHG+dOK5wHaDVNSgK2iJDz08ETvQayfOOgDvg==",
|
2354 |
+
"license": "MIT",
|
2355 |
+
"funding": {
|
2356 |
+
"type": "github",
|
2357 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2358 |
+
},
|
2359 |
+
"peerDependencies": {
|
2360 |
+
"@tiptap/pm": "^2.7.0"
|
2361 |
+
}
|
2362 |
+
},
|
2363 |
+
"node_modules/@tiptap/extension-blockquote": {
|
2364 |
+
"version": "2.10.0",
|
2365 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.10.0.tgz",
|
2366 |
+
"integrity": "sha512-6Xmfo2lpfIRcbfkLD/NGX4YgQqfgAbu6XaZQZf5oGtHLPTrz4D7Mw20GgNBHzae2XwUCwLMt6zXOkBgU/LnlZg==",
|
2367 |
+
"license": "MIT",
|
2368 |
+
"funding": {
|
2369 |
+
"type": "github",
|
2370 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2371 |
+
},
|
2372 |
+
"peerDependencies": {
|
2373 |
+
"@tiptap/core": "^2.7.0"
|
2374 |
+
}
|
2375 |
+
},
|
2376 |
+
"node_modules/@tiptap/extension-bold": {
|
2377 |
+
"version": "2.10.0",
|
2378 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.10.0.tgz",
|
2379 |
+
"integrity": "sha512-1wL8UI1Aii0u2cbDEvwyqsZb2pgBt8HLJdsIax/ELoF2tKCD5821nElqTGLBBg4pUGPa0ru9ZemuL8GdXZp3Qg==",
|
2380 |
+
"license": "MIT",
|
2381 |
+
"funding": {
|
2382 |
+
"type": "github",
|
2383 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2384 |
+
},
|
2385 |
+
"peerDependencies": {
|
2386 |
+
"@tiptap/core": "^2.7.0"
|
2387 |
+
}
|
2388 |
+
},
|
2389 |
+
"node_modules/@tiptap/extension-bullet-list": {
|
2390 |
+
"version": "2.10.0",
|
2391 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.10.0.tgz",
|
2392 |
+
"integrity": "sha512-Cl+DGu6D3SgF/hlKUDNet3gaZFy6cPEonOOkHwzXoybDXXdddFbaTvt9MLkBRUR3ldksXuVRP2/LwZsK5WyxJQ==",
|
2393 |
+
"license": "MIT",
|
2394 |
+
"funding": {
|
2395 |
+
"type": "github",
|
2396 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2397 |
+
},
|
2398 |
+
"peerDependencies": {
|
2399 |
+
"@tiptap/core": "^2.7.0"
|
2400 |
+
}
|
2401 |
+
},
|
2402 |
+
"node_modules/@tiptap/extension-code": {
|
2403 |
+
"version": "2.10.0",
|
2404 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.10.0.tgz",
|
2405 |
+
"integrity": "sha512-8JznKG1Jmv8gJezZGPoka8oRmfrcAAnMEOeMpKXjwMrIbQ6QynTZpqMGGVL1kfkZlLV84PYm+CGjGgjSsT4iZw==",
|
2406 |
+
"license": "MIT",
|
2407 |
+
"funding": {
|
2408 |
+
"type": "github",
|
2409 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2410 |
+
},
|
2411 |
+
"peerDependencies": {
|
2412 |
+
"@tiptap/core": "^2.7.0"
|
2413 |
+
}
|
2414 |
+
},
|
2415 |
+
"node_modules/@tiptap/extension-code-block": {
|
2416 |
+
"version": "2.10.0",
|
2417 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.10.0.tgz",
|
2418 |
+
"integrity": "sha512-QH+LP7L1s1EJlrDFnfgOP0q+Siqt0Zbkx4ICMcUGvEsycl53Ti8P0DRW7fAjRISdTCItuWJYvtmiYY7O3rYb+Q==",
|
2419 |
+
"license": "MIT",
|
2420 |
+
"funding": {
|
2421 |
+
"type": "github",
|
2422 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2423 |
+
},
|
2424 |
+
"peerDependencies": {
|
2425 |
+
"@tiptap/core": "^2.7.0",
|
2426 |
+
"@tiptap/pm": "^2.7.0"
|
2427 |
+
}
|
2428 |
+
},
|
2429 |
+
"node_modules/@tiptap/extension-code-block-lowlight": {
|
2430 |
+
"version": "2.10.0",
|
2431 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.10.0.tgz",
|
2432 |
+
"integrity": "sha512-dAv03XIHT5h+sdFmJzvx2FfpfFOOK9SBKHflRUdqTa8eA+0VZNAcPRjvJWVEWqts1fKZDJj774mO28NlhFzk9Q==",
|
2433 |
+
"license": "MIT",
|
2434 |
+
"funding": {
|
2435 |
+
"type": "github",
|
2436 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2437 |
+
},
|
2438 |
+
"peerDependencies": {
|
2439 |
+
"@tiptap/core": "^2.7.0",
|
2440 |
+
"@tiptap/extension-code-block": "^2.7.0",
|
2441 |
+
"@tiptap/pm": "^2.7.0",
|
2442 |
+
"highlight.js": "^11",
|
2443 |
+
"lowlight": "^2 || ^3"
|
2444 |
+
}
|
2445 |
+
},
|
2446 |
+
"node_modules/@tiptap/extension-document": {
|
2447 |
+
"version": "2.10.0",
|
2448 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.10.0.tgz",
|
2449 |
+
"integrity": "sha512-vseMW3EKiQAPgdbN48Y8F0nRqWhhrAo9DLacAfP7tu0x3uv44uotNjDBtAgp5QmJmqQVyrEdkLSZaU5vFzduhQ==",
|
2450 |
+
"license": "MIT",
|
2451 |
+
"funding": {
|
2452 |
+
"type": "github",
|
2453 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2454 |
+
},
|
2455 |
+
"peerDependencies": {
|
2456 |
+
"@tiptap/core": "^2.7.0"
|
2457 |
+
}
|
2458 |
+
},
|
2459 |
+
"node_modules/@tiptap/extension-dropcursor": {
|
2460 |
+
"version": "2.10.0",
|
2461 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.10.0.tgz",
|
2462 |
+
"integrity": "sha512-tifxp/a3NxTjLAuYBx9XAwVo4MSDoY/mQ8E18QtuXj0vuieCFxd8Bkyre0otubIAAQePXLTVGQoxPrKmMAa+Jg==",
|
2463 |
+
"license": "MIT",
|
2464 |
+
"funding": {
|
2465 |
+
"type": "github",
|
2466 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2467 |
+
},
|
2468 |
+
"peerDependencies": {
|
2469 |
+
"@tiptap/core": "^2.7.0",
|
2470 |
+
"@tiptap/pm": "^2.7.0"
|
2471 |
+
}
|
2472 |
+
},
|
2473 |
+
"node_modules/@tiptap/extension-gapcursor": {
|
2474 |
+
"version": "2.10.0",
|
2475 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.10.0.tgz",
|
2476 |
+
"integrity": "sha512-GViEnSnEBE74k7SYdXrQ4aXlKmWkrd9awdj/TgDSORgpZ4Dfyqtn+ENIWWby4NhL+BPM9P5hGCjkQXZsi6JKOw==",
|
2477 |
+
"license": "MIT",
|
2478 |
+
"funding": {
|
2479 |
+
"type": "github",
|
2480 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2481 |
+
},
|
2482 |
+
"peerDependencies": {
|
2483 |
+
"@tiptap/core": "^2.7.0",
|
2484 |
+
"@tiptap/pm": "^2.7.0"
|
2485 |
+
}
|
2486 |
+
},
|
2487 |
+
"node_modules/@tiptap/extension-hard-break": {
|
2488 |
+
"version": "2.10.0",
|
2489 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.10.0.tgz",
|
2490 |
+
"integrity": "sha512-NL/xPYUhhvQyCnOO5Yn+BlBOMLC1ru32nw7ox12TShGmaeKBrnV0DhzBRkyJU0MqCS26oWjieNPxfu0lR3oMSA==",
|
2491 |
+
"license": "MIT",
|
2492 |
+
"funding": {
|
2493 |
+
"type": "github",
|
2494 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2495 |
+
},
|
2496 |
+
"peerDependencies": {
|
2497 |
+
"@tiptap/core": "^2.7.0"
|
2498 |
+
}
|
2499 |
+
},
|
2500 |
+
"node_modules/@tiptap/extension-heading": {
|
2501 |
+
"version": "2.10.0",
|
2502 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.10.0.tgz",
|
2503 |
+
"integrity": "sha512-x2Uj5wrAHFaUdlChwLoQVmWtzZCuNyJpBRA19kA4idWL5z+6cIrUWepvwVBxA8ou6ictbzWW15o+blKtW7DlqA==",
|
2504 |
+
"license": "MIT",
|
2505 |
+
"funding": {
|
2506 |
+
"type": "github",
|
2507 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2508 |
+
},
|
2509 |
+
"peerDependencies": {
|
2510 |
+
"@tiptap/core": "^2.7.0"
|
2511 |
+
}
|
2512 |
+
},
|
2513 |
+
"node_modules/@tiptap/extension-highlight": {
|
2514 |
+
"version": "2.10.0",
|
2515 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.10.0.tgz",
|
2516 |
+
"integrity": "sha512-HU8UuKU7ljlzNn7jg29pM8QtIX7QvePcBjcWAt6K3qVwF1cbBNguIjKRY2rmoonU2nu8I6GknQNgV847kZifCQ==",
|
2517 |
+
"license": "MIT",
|
2518 |
+
"funding": {
|
2519 |
+
"type": "github",
|
2520 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2521 |
+
},
|
2522 |
+
"peerDependencies": {
|
2523 |
+
"@tiptap/core": "^2.7.0"
|
2524 |
+
}
|
2525 |
+
},
|
2526 |
+
"node_modules/@tiptap/extension-history": {
|
2527 |
+
"version": "2.10.0",
|
2528 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.10.0.tgz",
|
2529 |
+
"integrity": "sha512-5aYOmxqaCnw7e7wmWqFZmkpYCxxDjEzFbgVI6WknqNwqeOizR4+YJf3aAt/lTbksLJe47XF+NBX51gOm/ZBCiw==",
|
2530 |
+
"license": "MIT",
|
2531 |
+
"funding": {
|
2532 |
+
"type": "github",
|
2533 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2534 |
+
},
|
2535 |
+
"peerDependencies": {
|
2536 |
+
"@tiptap/core": "^2.7.0",
|
2537 |
+
"@tiptap/pm": "^2.7.0"
|
2538 |
+
}
|
2539 |
+
},
|
2540 |
+
"node_modules/@tiptap/extension-horizontal-rule": {
|
2541 |
+
"version": "2.10.0",
|
2542 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.10.0.tgz",
|
2543 |
+
"integrity": "sha512-el1SzI/x/h4HW8UltxJlyMSrRsO55ypKPLQHJC9h7F6kTTR31fJUzQa3AeTFrZvXS0kNHIFRpAMstw+N0L5TYg==",
|
2544 |
+
"license": "MIT",
|
2545 |
+
"funding": {
|
2546 |
+
"type": "github",
|
2547 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2548 |
+
},
|
2549 |
+
"peerDependencies": {
|
2550 |
+
"@tiptap/core": "^2.7.0",
|
2551 |
+
"@tiptap/pm": "^2.7.0"
|
2552 |
+
}
|
2553 |
+
},
|
2554 |
+
"node_modules/@tiptap/extension-italic": {
|
2555 |
+
"version": "2.10.0",
|
2556 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.10.0.tgz",
|
2557 |
+
"integrity": "sha512-MqPYbHAEeO8QBvZRIkF4J2OTf/uiUPzUiXGLJ50w1ozfMBIw1txMvfR3g2cpwfvZlcOgYTgy7M0Oq00nQz5eXg==",
|
2558 |
+
"license": "MIT",
|
2559 |
+
"funding": {
|
2560 |
+
"type": "github",
|
2561 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2562 |
+
},
|
2563 |
+
"peerDependencies": {
|
2564 |
+
"@tiptap/core": "^2.7.0"
|
2565 |
+
}
|
2566 |
+
},
|
2567 |
+
"node_modules/@tiptap/extension-list-item": {
|
2568 |
+
"version": "2.10.0",
|
2569 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.10.0.tgz",
|
2570 |
+
"integrity": "sha512-BxC6NNHd2xcC+mk5hpYWURUdj/mRz6TGFwH5CsyrUXPxApx0+V+EPHaAgdpu8dr+jtTEzjXF62V6e2JmOAPimg==",
|
2571 |
+
"license": "MIT",
|
2572 |
+
"funding": {
|
2573 |
+
"type": "github",
|
2574 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2575 |
+
},
|
2576 |
+
"peerDependencies": {
|
2577 |
+
"@tiptap/core": "^2.7.0"
|
2578 |
+
}
|
2579 |
+
},
|
2580 |
+
"node_modules/@tiptap/extension-ordered-list": {
|
2581 |
+
"version": "2.10.0",
|
2582 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.10.0.tgz",
|
2583 |
+
"integrity": "sha512-jsK+mvzs7HmxQuQOU3HgIga+v7zUbQlmSP4/danusqUihJ+lc1n0frDCIkVvJrnSB3FChvNgT6ZEA14HOhdJzg==",
|
2584 |
+
"license": "MIT",
|
2585 |
+
"funding": {
|
2586 |
+
"type": "github",
|
2587 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2588 |
+
},
|
2589 |
+
"peerDependencies": {
|
2590 |
+
"@tiptap/core": "^2.7.0"
|
2591 |
+
}
|
2592 |
+
},
|
2593 |
+
"node_modules/@tiptap/extension-paragraph": {
|
2594 |
+
"version": "2.10.0",
|
2595 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.10.0.tgz",
|
2596 |
+
"integrity": "sha512-4LUkVaJYjNdNZ7QOX6TRcA+m7oCtyrLGk49G22wl7XcPBkQPILP1mCUCU4f41bhjfhCgK5PPWP63kMtD+cEACg==",
|
2597 |
+
"license": "MIT",
|
2598 |
+
"funding": {
|
2599 |
+
"type": "github",
|
2600 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2601 |
+
},
|
2602 |
+
"peerDependencies": {
|
2603 |
+
"@tiptap/core": "^2.7.0"
|
2604 |
+
}
|
2605 |
+
},
|
2606 |
+
"node_modules/@tiptap/extension-placeholder": {
|
2607 |
+
"version": "2.10.0",
|
2608 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.10.0.tgz",
|
2609 |
+
"integrity": "sha512-1o6azk2plgYAFgMrV3prnBb1NZjl2V1T3wwnH4n3/h9z9lJ0v5BBAk9r+TRYSrcdXknwwHAWFYnQe6dc9buG2g==",
|
2610 |
+
"license": "MIT",
|
2611 |
+
"funding": {
|
2612 |
+
"type": "github",
|
2613 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2614 |
+
},
|
2615 |
+
"peerDependencies": {
|
2616 |
+
"@tiptap/core": "^2.7.0",
|
2617 |
+
"@tiptap/pm": "^2.7.0"
|
2618 |
+
}
|
2619 |
+
},
|
2620 |
+
"node_modules/@tiptap/extension-strike": {
|
2621 |
+
"version": "2.10.0",
|
2622 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.10.0.tgz",
|
2623 |
+
"integrity": "sha512-SxApLJMQkxnmPGR3lwaskvLK61yI+Bu9hGZGdwMZqNh6o3LoDOxDaXjHD5joeMYQiqQrBE9zg46506MsXtrU7Q==",
|
2624 |
+
"license": "MIT",
|
2625 |
+
"funding": {
|
2626 |
+
"type": "github",
|
2627 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2628 |
+
},
|
2629 |
+
"peerDependencies": {
|
2630 |
+
"@tiptap/core": "^2.7.0"
|
2631 |
+
}
|
2632 |
+
},
|
2633 |
+
"node_modules/@tiptap/extension-text": {
|
2634 |
+
"version": "2.10.0",
|
2635 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.10.0.tgz",
|
2636 |
+
"integrity": "sha512-SSnNncADS1KucdEcJlF6WGCs5+1pAhPrD68vlw34oj3NDT3Zh05KiyXsCV3Nw4wpHOnbWahV+z3uT2SnR+xgoQ==",
|
2637 |
+
"license": "MIT",
|
2638 |
+
"funding": {
|
2639 |
+
"type": "github",
|
2640 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2641 |
+
},
|
2642 |
+
"peerDependencies": {
|
2643 |
+
"@tiptap/core": "^2.7.0"
|
2644 |
+
}
|
2645 |
+
},
|
2646 |
+
"node_modules/@tiptap/extension-text-style": {
|
2647 |
+
"version": "2.10.0",
|
2648 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.10.0.tgz",
|
2649 |
+
"integrity": "sha512-VZtH1dp64wg1UcFtUPpRQK+kOm4JHBIv+WXuKX7EnpIEKjHKnyfV94BBVmaqY5UE4n3kbkkmIRB2Cmix/10AMg==",
|
2650 |
+
"license": "MIT",
|
2651 |
+
"funding": {
|
2652 |
+
"type": "github",
|
2653 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2654 |
+
},
|
2655 |
+
"peerDependencies": {
|
2656 |
+
"@tiptap/core": "^2.7.0"
|
2657 |
+
}
|
2658 |
+
},
|
2659 |
+
"node_modules/@tiptap/extension-typography": {
|
2660 |
+
"version": "2.10.0",
|
2661 |
+
"resolved": "https://registry.npmjs.org/@tiptap/extension-typography/-/extension-typography-2.10.0.tgz",
|
2662 |
+
"integrity": "sha512-03IOfJm4bk2hZ4SsSfxgBOVzcDxMRBlFD7ZY12H2EGNf1TKxj/0ANWhAH54FtquuOMoY5aWg5LZf0lk++8UDAw==",
|
2663 |
+
"license": "MIT",
|
2664 |
+
"funding": {
|
2665 |
+
"type": "github",
|
2666 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2667 |
+
},
|
2668 |
+
"peerDependencies": {
|
2669 |
+
"@tiptap/core": "^2.7.0"
|
2670 |
+
}
|
2671 |
+
},
|
2672 |
+
"node_modules/@tiptap/pm": {
|
2673 |
+
"version": "2.10.0",
|
2674 |
+
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.10.0.tgz",
|
2675 |
+
"integrity": "sha512-ohshlWf4MlW6D3rQkNQnhmiQ2w4pwRoQcJmTPt8UJoIDGkeKmZh494fQp4Aeh80XuGd81SsCv//1HJeyaeHJYQ==",
|
2676 |
+
"license": "MIT",
|
2677 |
+
"dependencies": {
|
2678 |
+
"prosemirror-changeset": "^2.2.1",
|
2679 |
+
"prosemirror-collab": "^1.3.1",
|
2680 |
+
"prosemirror-commands": "^1.6.2",
|
2681 |
+
"prosemirror-dropcursor": "^1.8.1",
|
2682 |
+
"prosemirror-gapcursor": "^1.3.2",
|
2683 |
+
"prosemirror-history": "^1.4.1",
|
2684 |
+
"prosemirror-inputrules": "^1.4.0",
|
2685 |
+
"prosemirror-keymap": "^1.2.2",
|
2686 |
+
"prosemirror-markdown": "^1.13.1",
|
2687 |
+
"prosemirror-menu": "^1.2.4",
|
2688 |
+
"prosemirror-model": "^1.23.0",
|
2689 |
+
"prosemirror-schema-basic": "^1.2.3",
|
2690 |
+
"prosemirror-schema-list": "^1.4.1",
|
2691 |
+
"prosemirror-state": "^1.4.3",
|
2692 |
+
"prosemirror-tables": "^1.6.1",
|
2693 |
+
"prosemirror-trailing-node": "^3.0.0",
|
2694 |
+
"prosemirror-transform": "^1.10.2",
|
2695 |
+
"prosemirror-view": "^1.36.0"
|
2696 |
+
},
|
2697 |
+
"funding": {
|
2698 |
+
"type": "github",
|
2699 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2700 |
+
}
|
2701 |
+
},
|
2702 |
+
"node_modules/@tiptap/starter-kit": {
|
2703 |
+
"version": "2.10.0",
|
2704 |
+
"resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.10.0.tgz",
|
2705 |
+
"integrity": "sha512-hMIM9a6HjYZo25EzhZHlKEIR7CFi0grRSOltEyggiyBuQqKFkI7iwCpZVVtviDV1FwV0EPANpIAxPS7aBRgFdg==",
|
2706 |
+
"license": "MIT",
|
2707 |
+
"dependencies": {
|
2708 |
+
"@tiptap/core": "^2.10.0",
|
2709 |
+
"@tiptap/extension-blockquote": "^2.10.0",
|
2710 |
+
"@tiptap/extension-bold": "^2.10.0",
|
2711 |
+
"@tiptap/extension-bullet-list": "^2.10.0",
|
2712 |
+
"@tiptap/extension-code": "^2.10.0",
|
2713 |
+
"@tiptap/extension-code-block": "^2.10.0",
|
2714 |
+
"@tiptap/extension-document": "^2.10.0",
|
2715 |
+
"@tiptap/extension-dropcursor": "^2.10.0",
|
2716 |
+
"@tiptap/extension-gapcursor": "^2.10.0",
|
2717 |
+
"@tiptap/extension-hard-break": "^2.10.0",
|
2718 |
+
"@tiptap/extension-heading": "^2.10.0",
|
2719 |
+
"@tiptap/extension-history": "^2.10.0",
|
2720 |
+
"@tiptap/extension-horizontal-rule": "^2.10.0",
|
2721 |
+
"@tiptap/extension-italic": "^2.10.0",
|
2722 |
+
"@tiptap/extension-list-item": "^2.10.0",
|
2723 |
+
"@tiptap/extension-ordered-list": "^2.10.0",
|
2724 |
+
"@tiptap/extension-paragraph": "^2.10.0",
|
2725 |
+
"@tiptap/extension-strike": "^2.10.0",
|
2726 |
+
"@tiptap/extension-text": "^2.10.0",
|
2727 |
+
"@tiptap/extension-text-style": "^2.10.0",
|
2728 |
+
"@tiptap/pm": "^2.10.0"
|
2729 |
+
},
|
2730 |
+
"funding": {
|
2731 |
+
"type": "github",
|
2732 |
+
"url": "https://github.com/sponsors/ueberdosis"
|
2733 |
+
}
|
2734 |
+
},
|
2735 |
"node_modules/@types/cookie": {
|
2736 |
"version": "0.6.0",
|
2737 |
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
|
|
|
2811 |
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
2812 |
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
2813 |
},
|
2814 |
+
"node_modules/@types/hast": {
|
2815 |
+
"version": "3.0.4",
|
2816 |
+
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
|
2817 |
+
"integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
|
2818 |
+
"license": "MIT",
|
2819 |
+
"peer": true,
|
2820 |
+
"dependencies": {
|
2821 |
+
"@types/unist": "*"
|
2822 |
+
}
|
2823 |
+
},
|
2824 |
"node_modules/@types/json-schema": {
|
2825 |
"version": "7.0.15",
|
2826 |
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
|
|
3841 |
"ieee754": "^1.2.1"
|
3842 |
}
|
3843 |
},
|
3844 |
+
"node_modules/buffer-builder": {
|
3845 |
+
"version": "0.2.0",
|
3846 |
+
"resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz",
|
3847 |
+
"integrity": "sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==",
|
3848 |
+
"devOptional": true,
|
3849 |
+
"license": "MIT/X11"
|
3850 |
+
},
|
3851 |
"node_modules/buffer-crc32": {
|
3852 |
"version": "0.2.13",
|
3853 |
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
|
|
4321 |
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
|
4322 |
"dev": true
|
4323 |
},
|
4324 |
+
"node_modules/colorjs.io": {
|
4325 |
+
"version": "0.5.2",
|
4326 |
+
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
|
4327 |
+
"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
|
4328 |
+
"devOptional": true,
|
4329 |
+
"license": "MIT"
|
4330 |
+
},
|
4331 |
"node_modules/colors": {
|
4332 |
"version": "1.4.0",
|
4333 |
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
|
|
|
5190 |
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz",
|
5191 |
"integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw=="
|
5192 |
},
|
5193 |
+
"node_modules/devlop": {
|
5194 |
+
"version": "1.1.0",
|
5195 |
+
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
|
5196 |
+
"integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
|
5197 |
+
"license": "MIT",
|
5198 |
+
"peer": true,
|
5199 |
+
"dependencies": {
|
5200 |
+
"dequal": "^2.0.0"
|
5201 |
+
},
|
5202 |
+
"funding": {
|
5203 |
+
"type": "github",
|
5204 |
+
"url": "https://github.com/sponsors/wooorm"
|
5205 |
+
}
|
5206 |
+
},
|
5207 |
"node_modules/didyoumean": {
|
5208 |
"version": "1.2.2",
|
5209 |
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
|
|
5491 |
"version": "4.0.0",
|
5492 |
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
5493 |
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
|
|
5494 |
"engines": {
|
5495 |
"node": ">=10"
|
5496 |
},
|
|
|
6421 |
"version": "4.0.0",
|
6422 |
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
6423 |
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
6424 |
+
"devOptional": true,
|
6425 |
"engines": {
|
6426 |
"node": ">=8"
|
6427 |
}
|
|
|
6684 |
"node": ">= 4"
|
6685 |
}
|
6686 |
},
|
6687 |
+
"node_modules/immutable": {
|
6688 |
+
"version": "5.0.3",
|
6689 |
+
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz",
|
6690 |
+
"integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==",
|
6691 |
+
"devOptional": true,
|
6692 |
+
"license": "MIT"
|
6693 |
+
},
|
6694 |
"node_modules/import-fresh": {
|
6695 |
"version": "3.3.0",
|
6696 |
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
|
|
7432 |
"get-func-name": "^2.0.1"
|
7433 |
}
|
7434 |
},
|
7435 |
+
"node_modules/lowlight": {
|
7436 |
+
"version": "3.1.0",
|
7437 |
+
"resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.1.0.tgz",
|
7438 |
+
"integrity": "sha512-CEbNVoSikAxwDMDPjXlqlFYiZLkDJHwyGu/MfOsJnF3d7f3tds5J3z8s/l9TMXhzfsJCCJEAsD78842mwmg0PQ==",
|
7439 |
+
"license": "MIT",
|
7440 |
+
"peer": true,
|
7441 |
+
"dependencies": {
|
7442 |
+
"@types/hast": "^3.0.0",
|
7443 |
+
"devlop": "^1.0.0",
|
7444 |
+
"highlight.js": "~11.9.0"
|
7445 |
+
},
|
7446 |
+
"funding": {
|
7447 |
+
"type": "github",
|
7448 |
+
"url": "https://github.com/sponsors/wooorm"
|
7449 |
+
}
|
7450 |
+
},
|
7451 |
"node_modules/magic-string": {
|
7452 |
"version": "0.30.11",
|
7453 |
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
|
|
|
9070 |
"node": "10.* || >= 12.*"
|
9071 |
}
|
9072 |
},
|
9073 |
+
"node_modules/prosemirror-changeset": {
|
9074 |
+
"version": "2.2.1",
|
9075 |
+
"resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz",
|
9076 |
+
"integrity": "sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==",
|
9077 |
+
"license": "MIT",
|
9078 |
"dependencies": {
|
|
|
|
|
9079 |
"prosemirror-transform": "^1.0.0"
|
9080 |
}
|
9081 |
},
|
9082 |
+
"node_modules/prosemirror-collab": {
|
9083 |
+
"version": "1.3.1",
|
9084 |
+
"resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
|
9085 |
+
"integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
|
9086 |
+
"license": "MIT",
|
9087 |
+
"dependencies": {
|
9088 |
+
"prosemirror-state": "^1.0.0"
|
9089 |
+
}
|
9090 |
+
},
|
9091 |
+
"node_modules/prosemirror-commands": {
|
9092 |
+
"version": "1.6.2",
|
9093 |
+
"resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.6.2.tgz",
|
9094 |
+
"integrity": "sha512-0nDHH++qcf/BuPLYvmqZTUUsPJUCPBUXt0J1ErTcDIS369CTp773itzLGIgIXG4LJXOlwYCr44+Mh4ii6MP1QA==",
|
9095 |
+
"license": "MIT",
|
9096 |
+
"dependencies": {
|
9097 |
+
"prosemirror-model": "^1.0.0",
|
9098 |
+
"prosemirror-state": "^1.0.0",
|
9099 |
+
"prosemirror-transform": "^1.10.2"
|
9100 |
+
}
|
9101 |
+
},
|
9102 |
+
"node_modules/prosemirror-dropcursor": {
|
9103 |
"version": "1.8.1",
|
9104 |
"resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz",
|
9105 |
"integrity": "sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==",
|
|
|
9222 |
"prosemirror-view": "^1.27.0"
|
9223 |
}
|
9224 |
},
|
9225 |
+
"node_modules/prosemirror-tables": {
|
9226 |
+
"version": "1.6.1",
|
9227 |
+
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.6.1.tgz",
|
9228 |
+
"integrity": "sha512-p8WRJNA96jaNQjhJolmbxTzd6M4huRE5xQ8OxjvMhQUP0Nzpo4zz6TztEiwk6aoqGBhz9lxRWR1yRZLlpQN98w==",
|
9229 |
+
"license": "MIT",
|
9230 |
+
"dependencies": {
|
9231 |
+
"prosemirror-keymap": "^1.1.2",
|
9232 |
+
"prosemirror-model": "^1.8.1",
|
9233 |
+
"prosemirror-state": "^1.3.1",
|
9234 |
+
"prosemirror-transform": "^1.2.1",
|
9235 |
+
"prosemirror-view": "^1.13.3"
|
9236 |
+
}
|
9237 |
+
},
|
9238 |
+
"node_modules/prosemirror-trailing-node": {
|
9239 |
+
"version": "3.0.0",
|
9240 |
+
"resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz",
|
9241 |
+
"integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==",
|
9242 |
+
"license": "MIT",
|
9243 |
+
"dependencies": {
|
9244 |
+
"@remirror/core-constants": "3.0.0",
|
9245 |
+
"escape-string-regexp": "^4.0.0"
|
9246 |
+
},
|
9247 |
+
"peerDependencies": {
|
9248 |
+
"prosemirror-model": "^1.22.1",
|
9249 |
+
"prosemirror-state": "^1.4.2",
|
9250 |
+
"prosemirror-view": "^1.33.8"
|
9251 |
+
}
|
9252 |
+
},
|
9253 |
"node_modules/prosemirror-transform": {
|
9254 |
+
"version": "1.10.2",
|
9255 |
+
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.2.tgz",
|
9256 |
+
"integrity": "sha512-2iUq0wv2iRoJO/zj5mv8uDUriOHWzXRnOTVgCzSXnktS/2iQRa3UUQwVlkBlYZFtygw6Nh1+X4mGqoYBINn5KQ==",
|
9257 |
+
"license": "MIT",
|
9258 |
"dependencies": {
|
9259 |
"prosemirror-model": "^1.21.0"
|
9260 |
}
|
9261 |
},
|
9262 |
"node_modules/prosemirror-view": {
|
9263 |
+
"version": "1.36.0",
|
9264 |
+
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.36.0.tgz",
|
9265 |
+
"integrity": "sha512-U0GQd5yFvV5qUtT41X1zCQfbw14vkbbKwLlQXhdylEmgpYVHkefXYcC4HHwWOfZa3x6Y8wxDLUBv7dxN5XQ3nA==",
|
9266 |
+
"license": "MIT",
|
9267 |
"dependencies": {
|
9268 |
"prosemirror-model": "^1.20.0",
|
9269 |
"prosemirror-state": "^1.0.0",
|
|
|
9751 |
"version": "7.8.1",
|
9752 |
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
|
9753 |
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
|
9754 |
+
"devOptional": true,
|
9755 |
"dependencies": {
|
9756 |
"tslib": "^2.1.0"
|
9757 |
}
|
|
|
9844 |
"rimraf": "bin.js"
|
9845 |
}
|
9846 |
},
|
9847 |
+
"node_modules/sass-embedded": {
|
9848 |
+
"version": "1.81.0",
|
9849 |
+
"resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.81.0.tgz",
|
9850 |
+
"integrity": "sha512-uZQ2Faxb1oWBHpeSSzjxnhClbMb3QadN0ql0ZFNuqWOLUxwaVhrMlMhPq6TDPbbfDUjihuwrMCuy695Bgna5RA==",
|
9851 |
+
"devOptional": true,
|
9852 |
+
"license": "MIT",
|
9853 |
+
"dependencies": {
|
9854 |
+
"@bufbuild/protobuf": "^2.0.0",
|
9855 |
+
"buffer-builder": "^0.2.0",
|
9856 |
+
"colorjs.io": "^0.5.0",
|
9857 |
+
"immutable": "^5.0.2",
|
9858 |
+
"rxjs": "^7.4.0",
|
9859 |
+
"supports-color": "^8.1.1",
|
9860 |
+
"sync-child-process": "^1.0.2",
|
9861 |
+
"varint": "^6.0.0"
|
9862 |
+
},
|
9863 |
+
"bin": {
|
9864 |
+
"sass": "dist/bin/sass.js"
|
9865 |
+
},
|
9866 |
+
"engines": {
|
9867 |
+
"node": ">=16.0.0"
|
9868 |
+
},
|
9869 |
+
"optionalDependencies": {
|
9870 |
+
"sass-embedded-android-arm": "1.81.0",
|
9871 |
+
"sass-embedded-android-arm64": "1.81.0",
|
9872 |
+
"sass-embedded-android-ia32": "1.81.0",
|
9873 |
+
"sass-embedded-android-riscv64": "1.81.0",
|
9874 |
+
"sass-embedded-android-x64": "1.81.0",
|
9875 |
+
"sass-embedded-darwin-arm64": "1.81.0",
|
9876 |
+
"sass-embedded-darwin-x64": "1.81.0",
|
9877 |
+
"sass-embedded-linux-arm": "1.81.0",
|
9878 |
+
"sass-embedded-linux-arm64": "1.81.0",
|
9879 |
+
"sass-embedded-linux-ia32": "1.81.0",
|
9880 |
+
"sass-embedded-linux-musl-arm": "1.81.0",
|
9881 |
+
"sass-embedded-linux-musl-arm64": "1.81.0",
|
9882 |
+
"sass-embedded-linux-musl-ia32": "1.81.0",
|
9883 |
+
"sass-embedded-linux-musl-riscv64": "1.81.0",
|
9884 |
+
"sass-embedded-linux-musl-x64": "1.81.0",
|
9885 |
+
"sass-embedded-linux-riscv64": "1.81.0",
|
9886 |
+
"sass-embedded-linux-x64": "1.81.0",
|
9887 |
+
"sass-embedded-win32-arm64": "1.81.0",
|
9888 |
+
"sass-embedded-win32-ia32": "1.81.0",
|
9889 |
+
"sass-embedded-win32-x64": "1.81.0"
|
9890 |
+
}
|
9891 |
+
},
|
9892 |
+
"node_modules/sass-embedded-android-arm": {
|
9893 |
+
"version": "1.81.0",
|
9894 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.81.0.tgz",
|
9895 |
+
"integrity": "sha512-NWEmIuaIEsGFNsIRa+5JpIpPJyZ32H15E85CNZqEIhhwWlk9UNw7vlOCmTH8MtabtnACwC/2NG8VyNa3nxKzUQ==",
|
9896 |
+
"cpu": [
|
9897 |
+
"arm"
|
9898 |
+
],
|
9899 |
+
"license": "MIT",
|
9900 |
+
"optional": true,
|
9901 |
+
"os": [
|
9902 |
+
"android"
|
9903 |
+
],
|
9904 |
+
"engines": {
|
9905 |
+
"node": ">=14.0.0"
|
9906 |
+
}
|
9907 |
+
},
|
9908 |
+
"node_modules/sass-embedded-android-arm64": {
|
9909 |
+
"version": "1.81.0",
|
9910 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.81.0.tgz",
|
9911 |
+
"integrity": "sha512-I36P77/PKAHx6sqOmexO2iEY5kpsmQ1VxcgITZSOxPMQhdB6m4t3bTabfDuWQQmCrqqiNFtLQHeytB65bUqwiw==",
|
9912 |
+
"cpu": [
|
9913 |
+
"arm64"
|
9914 |
+
],
|
9915 |
+
"license": "MIT",
|
9916 |
+
"optional": true,
|
9917 |
+
"os": [
|
9918 |
+
"android"
|
9919 |
+
],
|
9920 |
+
"engines": {
|
9921 |
+
"node": ">=14.0.0"
|
9922 |
+
}
|
9923 |
+
},
|
9924 |
+
"node_modules/sass-embedded-android-ia32": {
|
9925 |
+
"version": "1.81.0",
|
9926 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.81.0.tgz",
|
9927 |
+
"integrity": "sha512-k8V1usXw30w1GVxvrteG1RzgYJzYQ9PfL2aeOqGdroBN7zYTD9VGJXTGcxA4IeeRxmRd7szVW2mKXXS472fh8g==",
|
9928 |
+
"cpu": [
|
9929 |
+
"ia32"
|
9930 |
+
],
|
9931 |
+
"license": "MIT",
|
9932 |
+
"optional": true,
|
9933 |
+
"os": [
|
9934 |
+
"android"
|
9935 |
+
],
|
9936 |
+
"engines": {
|
9937 |
+
"node": ">=14.0.0"
|
9938 |
+
}
|
9939 |
+
},
|
9940 |
+
"node_modules/sass-embedded-android-riscv64": {
|
9941 |
+
"version": "1.81.0",
|
9942 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.81.0.tgz",
|
9943 |
+
"integrity": "sha512-RXlanyLXEpN/DEehXgLuKPsqT//GYlsGFxKXgRiCc8hIPAueFLQXKJmLWlL3BEtHgmFdbsStIu4aZCcb1hOFlQ==",
|
9944 |
+
"cpu": [
|
9945 |
+
"riscv64"
|
9946 |
+
],
|
9947 |
+
"license": "MIT",
|
9948 |
+
"optional": true,
|
9949 |
+
"os": [
|
9950 |
+
"android"
|
9951 |
+
],
|
9952 |
+
"engines": {
|
9953 |
+
"node": ">=14.0.0"
|
9954 |
+
}
|
9955 |
+
},
|
9956 |
+
"node_modules/sass-embedded-android-x64": {
|
9957 |
+
"version": "1.81.0",
|
9958 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.81.0.tgz",
|
9959 |
+
"integrity": "sha512-RQG0FxGQ1DERNyUDED8+BDVaLIjI+BNg8lVcyqlLZUrWY6NhzjwYEeiN/DNZmMmHtqDucAPNDcsdVUNQqsBy2A==",
|
9960 |
+
"cpu": [
|
9961 |
+
"x64"
|
9962 |
+
],
|
9963 |
+
"license": "MIT",
|
9964 |
+
"optional": true,
|
9965 |
+
"os": [
|
9966 |
+
"android"
|
9967 |
+
],
|
9968 |
+
"engines": {
|
9969 |
+
"node": ">=14.0.0"
|
9970 |
+
}
|
9971 |
+
},
|
9972 |
+
"node_modules/sass-embedded-darwin-arm64": {
|
9973 |
+
"version": "1.81.0",
|
9974 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.81.0.tgz",
|
9975 |
+
"integrity": "sha512-gLKbsfII9Ppua76N41ODFnKGutla9qv0OGAas8gxe0jYBeAQFi/1iKQYdNtQtKi4mA9n5TQTqz+HHCKszZCoyA==",
|
9976 |
+
"cpu": [
|
9977 |
+
"arm64"
|
9978 |
+
],
|
9979 |
+
"license": "MIT",
|
9980 |
+
"optional": true,
|
9981 |
+
"os": [
|
9982 |
+
"darwin"
|
9983 |
+
],
|
9984 |
+
"engines": {
|
9985 |
+
"node": ">=14.0.0"
|
9986 |
+
}
|
9987 |
+
},
|
9988 |
+
"node_modules/sass-embedded-darwin-x64": {
|
9989 |
+
"version": "1.81.0",
|
9990 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.81.0.tgz",
|
9991 |
+
"integrity": "sha512-7uMOlT9hD2KUJCbTN2XcfghDxt/rc50ujjfSjSHjX1SYj7mGplkINUXvVbbvvaV2wt6t9vkGkCo5qNbeBhfwBg==",
|
9992 |
+
"cpu": [
|
9993 |
+
"x64"
|
9994 |
+
],
|
9995 |
+
"license": "MIT",
|
9996 |
+
"optional": true,
|
9997 |
+
"os": [
|
9998 |
+
"darwin"
|
9999 |
+
],
|
10000 |
+
"engines": {
|
10001 |
+
"node": ">=14.0.0"
|
10002 |
+
}
|
10003 |
+
},
|
10004 |
+
"node_modules/sass-embedded-linux-arm": {
|
10005 |
+
"version": "1.81.0",
|
10006 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.81.0.tgz",
|
10007 |
+
"integrity": "sha512-REqR9qM4RchCE3cKqzRy9Q4zigIV82SbSpCi/O4O3oK3pg2I1z7vkb3TiJsivusG/li7aqKZGmYOtAXjruGQDA==",
|
10008 |
+
"cpu": [
|
10009 |
+
"arm"
|
10010 |
+
],
|
10011 |
+
"license": "MIT",
|
10012 |
+
"optional": true,
|
10013 |
+
"os": [
|
10014 |
+
"linux"
|
10015 |
+
],
|
10016 |
+
"engines": {
|
10017 |
+
"node": ">=14.0.0"
|
10018 |
+
}
|
10019 |
+
},
|
10020 |
+
"node_modules/sass-embedded-linux-arm64": {
|
10021 |
+
"version": "1.81.0",
|
10022 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.81.0.tgz",
|
10023 |
+
"integrity": "sha512-jy4bvhdUmqbyw1jv1f3Uxl+MF8EU/Y/GDx4w6XPJm4Ds+mwH/TwnyAwsxxoBhWfnBnW8q2ADy039DlS5p+9csQ==",
|
10024 |
+
"cpu": [
|
10025 |
+
"arm64"
|
10026 |
+
],
|
10027 |
+
"license": "MIT",
|
10028 |
+
"optional": true,
|
10029 |
+
"os": [
|
10030 |
+
"linux"
|
10031 |
+
],
|
10032 |
+
"engines": {
|
10033 |
+
"node": ">=14.0.0"
|
10034 |
+
}
|
10035 |
+
},
|
10036 |
+
"node_modules/sass-embedded-linux-ia32": {
|
10037 |
+
"version": "1.81.0",
|
10038 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.81.0.tgz",
|
10039 |
+
"integrity": "sha512-ga/Jk4q5Bn1aC+iHJteDZuLSKnmBUiS3dEg1fnl/Z7GaHIChceKDJOw0zNaILRXI0qT2E1at9MwzoRaRA5Nn/g==",
|
10040 |
+
"cpu": [
|
10041 |
+
"ia32"
|
10042 |
+
],
|
10043 |
+
"license": "MIT",
|
10044 |
+
"optional": true,
|
10045 |
+
"os": [
|
10046 |
+
"linux"
|
10047 |
+
],
|
10048 |
+
"engines": {
|
10049 |
+
"node": ">=14.0.0"
|
10050 |
+
}
|
10051 |
+
},
|
10052 |
+
"node_modules/sass-embedded-linux-musl-arm": {
|
10053 |
+
"version": "1.81.0",
|
10054 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.81.0.tgz",
|
10055 |
+
"integrity": "sha512-oWVUvQ4d5Kx1Md75YXZl5z1WBjc+uOhfRRqzkJ3nWc8tjszxJN+y/5EOJavhsNI3/2yoTt6eMXRTqDD9b0tWSQ==",
|
10056 |
+
"cpu": [
|
10057 |
+
"arm"
|
10058 |
+
],
|
10059 |
+
"license": "MIT",
|
10060 |
+
"optional": true,
|
10061 |
+
"os": [
|
10062 |
+
"linux"
|
10063 |
+
],
|
10064 |
+
"engines": {
|
10065 |
+
"node": ">=14.0.0"
|
10066 |
+
}
|
10067 |
+
},
|
10068 |
+
"node_modules/sass-embedded-linux-musl-arm64": {
|
10069 |
+
"version": "1.81.0",
|
10070 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.81.0.tgz",
|
10071 |
+
"integrity": "sha512-hpntWf5kjkoxncA1Vh8vhsUOquZ8AROZKx0rQh7ZjSRs4JrYZASz1cfevPKaEM3wIim/nYa6TJqm0VqWsrERlA==",
|
10072 |
+
"cpu": [
|
10073 |
+
"arm64"
|
10074 |
+
],
|
10075 |
+
"license": "MIT",
|
10076 |
+
"optional": true,
|
10077 |
+
"os": [
|
10078 |
+
"linux"
|
10079 |
+
],
|
10080 |
+
"engines": {
|
10081 |
+
"node": ">=14.0.0"
|
10082 |
+
}
|
10083 |
+
},
|
10084 |
+
"node_modules/sass-embedded-linux-musl-ia32": {
|
10085 |
+
"version": "1.81.0",
|
10086 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.81.0.tgz",
|
10087 |
+
"integrity": "sha512-UEXUYkBuqTSwg5JNWiNlfMZ1Jx6SJkaEdx+fsL3Tk099L8cKSoJWH2EPz4ZJjNbyIMymrSdVfymheTeZ8u24xA==",
|
10088 |
+
"cpu": [
|
10089 |
+
"ia32"
|
10090 |
+
],
|
10091 |
+
"license": "MIT",
|
10092 |
+
"optional": true,
|
10093 |
+
"os": [
|
10094 |
+
"linux"
|
10095 |
+
],
|
10096 |
+
"engines": {
|
10097 |
+
"node": ">=14.0.0"
|
10098 |
+
}
|
10099 |
+
},
|
10100 |
+
"node_modules/sass-embedded-linux-musl-riscv64": {
|
10101 |
+
"version": "1.81.0",
|
10102 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.81.0.tgz",
|
10103 |
+
"integrity": "sha512-1D7OznytbIhx2XDHWi1nuQ8d/uCVR7FGGzELgaU//T8A9DapVTUgPKvB70AF1k4GzChR9IXU/WvFZs2hDTbaJg==",
|
10104 |
+
"cpu": [
|
10105 |
+
"riscv64"
|
10106 |
+
],
|
10107 |
+
"license": "MIT",
|
10108 |
+
"optional": true,
|
10109 |
+
"os": [
|
10110 |
+
"linux"
|
10111 |
+
],
|
10112 |
+
"engines": {
|
10113 |
+
"node": ">=14.0.0"
|
10114 |
+
}
|
10115 |
+
},
|
10116 |
+
"node_modules/sass-embedded-linux-musl-x64": {
|
10117 |
+
"version": "1.81.0",
|
10118 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.81.0.tgz",
|
10119 |
+
"integrity": "sha512-ia6VCTeVDQtBSMktXRFza1AZCt8/6aUoujot6Ugf4KmdytQqPJIHxkHaGftm5xwi9WdrMGYS7zgolToPijR11A==",
|
10120 |
+
"cpu": [
|
10121 |
+
"x64"
|
10122 |
+
],
|
10123 |
+
"license": "MIT",
|
10124 |
+
"optional": true,
|
10125 |
+
"os": [
|
10126 |
+
"linux"
|
10127 |
+
],
|
10128 |
+
"engines": {
|
10129 |
+
"node": ">=14.0.0"
|
10130 |
+
}
|
10131 |
+
},
|
10132 |
+
"node_modules/sass-embedded-linux-riscv64": {
|
10133 |
+
"version": "1.81.0",
|
10134 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.81.0.tgz",
|
10135 |
+
"integrity": "sha512-KbxSsqu4tT1XbhZfJV/5NfW0VtJIGlD58RjqJqJBi8Rnjrx29/upBsuwoDWtsPV/LhoGwwU1XkSa9Q1ifCz4fQ==",
|
10136 |
+
"cpu": [
|
10137 |
+
"riscv64"
|
10138 |
+
],
|
10139 |
+
"license": "MIT",
|
10140 |
+
"optional": true,
|
10141 |
+
"os": [
|
10142 |
+
"linux"
|
10143 |
+
],
|
10144 |
+
"engines": {
|
10145 |
+
"node": ">=14.0.0"
|
10146 |
+
}
|
10147 |
+
},
|
10148 |
+
"node_modules/sass-embedded-linux-x64": {
|
10149 |
+
"version": "1.81.0",
|
10150 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.81.0.tgz",
|
10151 |
+
"integrity": "sha512-AMDeVY2T9WAnSFkuQcsOn5c29GRs/TuqnCiblKeXfxCSKym5uKdBl/N7GnTV6OjzoxiJBbkYKdVIaS5By7Gj4g==",
|
10152 |
+
"cpu": [
|
10153 |
+
"x64"
|
10154 |
+
],
|
10155 |
+
"license": "MIT",
|
10156 |
+
"optional": true,
|
10157 |
+
"os": [
|
10158 |
+
"linux"
|
10159 |
+
],
|
10160 |
+
"engines": {
|
10161 |
+
"node": ">=14.0.0"
|
10162 |
+
}
|
10163 |
+
},
|
10164 |
+
"node_modules/sass-embedded-win32-arm64": {
|
10165 |
+
"version": "1.81.0",
|
10166 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.81.0.tgz",
|
10167 |
+
"integrity": "sha512-YOmBRYnygwWUmCoH14QbMRHjcvCJufeJBAp0m61tOJXIQh64ziwV4mjdqjS/Rx3zhTT4T+nulDUw4d3kLiMncA==",
|
10168 |
+
"cpu": [
|
10169 |
+
"arm64"
|
10170 |
+
],
|
10171 |
+
"license": "MIT",
|
10172 |
+
"optional": true,
|
10173 |
+
"os": [
|
10174 |
+
"win32"
|
10175 |
+
],
|
10176 |
+
"engines": {
|
10177 |
+
"node": ">=14.0.0"
|
10178 |
+
}
|
10179 |
+
},
|
10180 |
+
"node_modules/sass-embedded-win32-ia32": {
|
10181 |
+
"version": "1.81.0",
|
10182 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.81.0.tgz",
|
10183 |
+
"integrity": "sha512-HFfr/C+uLJGGTENdnssuNTmXI/xnIasUuEHEKqI+2J0FHCWT5cpz3PGAOHymPyJcZVYGUG/7gIxIx/d7t0LFYw==",
|
10184 |
+
"cpu": [
|
10185 |
+
"ia32"
|
10186 |
+
],
|
10187 |
+
"license": "MIT",
|
10188 |
+
"optional": true,
|
10189 |
+
"os": [
|
10190 |
+
"win32"
|
10191 |
+
],
|
10192 |
+
"engines": {
|
10193 |
+
"node": ">=14.0.0"
|
10194 |
+
}
|
10195 |
+
},
|
10196 |
+
"node_modules/sass-embedded-win32-x64": {
|
10197 |
+
"version": "1.81.0",
|
10198 |
+
"resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.81.0.tgz",
|
10199 |
+
"integrity": "sha512-wxj52jDcIAwWcXb7ShZ7vQYKcVUkJ+04YM9l46jDY+qwHzliGuorAUyujLyKTE9heGD3gShJ3wPPC1lXzq6v9A==",
|
10200 |
+
"cpu": [
|
10201 |
+
"x64"
|
10202 |
+
],
|
10203 |
+
"license": "MIT",
|
10204 |
+
"optional": true,
|
10205 |
+
"os": [
|
10206 |
+
"win32"
|
10207 |
+
],
|
10208 |
+
"engines": {
|
10209 |
+
"node": ">=14.0.0"
|
10210 |
+
}
|
10211 |
+
},
|
10212 |
+
"node_modules/sass-embedded/node_modules/supports-color": {
|
10213 |
+
"version": "8.1.1",
|
10214 |
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
10215 |
+
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
10216 |
+
"devOptional": true,
|
10217 |
+
"license": "MIT",
|
10218 |
+
"dependencies": {
|
10219 |
+
"has-flag": "^4.0.0"
|
10220 |
+
},
|
10221 |
+
"engines": {
|
10222 |
+
"node": ">=10"
|
10223 |
+
},
|
10224 |
+
"funding": {
|
10225 |
+
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
10226 |
+
}
|
10227 |
+
},
|
10228 |
"node_modules/semver": {
|
10229 |
"version": "7.6.3",
|
10230 |
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
|
|
10940 |
"integrity": "sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA==",
|
10941 |
"dev": true
|
10942 |
},
|
10943 |
+
"node_modules/sync-child-process": {
|
10944 |
+
"version": "1.0.2",
|
10945 |
+
"resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz",
|
10946 |
+
"integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==",
|
10947 |
+
"devOptional": true,
|
10948 |
+
"license": "MIT",
|
10949 |
+
"dependencies": {
|
10950 |
+
"sync-message-port": "^1.0.0"
|
10951 |
+
},
|
10952 |
+
"engines": {
|
10953 |
+
"node": ">=16.0.0"
|
10954 |
+
}
|
10955 |
+
},
|
10956 |
+
"node_modules/sync-message-port": {
|
10957 |
+
"version": "1.1.3",
|
10958 |
+
"resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.1.3.tgz",
|
10959 |
+
"integrity": "sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==",
|
10960 |
+
"devOptional": true,
|
10961 |
+
"license": "MIT",
|
10962 |
+
"engines": {
|
10963 |
+
"node": ">=16.0.0"
|
10964 |
+
}
|
10965 |
+
},
|
10966 |
"node_modules/tabbable": {
|
10967 |
"version": "6.2.0",
|
10968 |
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
|
|
|
11335 |
"version": "7.2.0",
|
11336 |
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz",
|
11337 |
"integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==",
|
11338 |
+
"license": "MIT",
|
11339 |
"dependencies": {
|
11340 |
"@mixmark-io/domino": "^2.2.0"
|
11341 |
}
|
|
|
11549 |
"node": ">= 10.13.0"
|
11550 |
}
|
11551 |
},
|
11552 |
+
"node_modules/varint": {
|
11553 |
+
"version": "6.0.0",
|
11554 |
+
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
|
11555 |
+
"integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
|
11556 |
+
"devOptional": true,
|
11557 |
+
"license": "MIT"
|
11558 |
+
},
|
11559 |
"node_modules/verror": {
|
11560 |
"version": "1.10.0",
|
11561 |
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
{
|
2 |
"name": "open-webui",
|
3 |
-
"version": "0.4.
|
4 |
"private": true,
|
5 |
"scripts": {
|
6 |
"dev": "npm run pyodide:fetch && vite dev --host",
|
@@ -37,6 +37,7 @@
|
|
37 |
"postcss": "^8.4.31",
|
38 |
"prettier": "^3.3.3",
|
39 |
"prettier-plugin-svelte": "^3.2.6",
|
|
|
40 |
"svelte": "^4.2.18",
|
41 |
"svelte-check": "^3.8.5",
|
42 |
"svelte-confetti": "^1.3.2",
|
@@ -56,6 +57,13 @@
|
|
56 |
"@mediapipe/tasks-vision": "^0.10.17",
|
57 |
"@pyscript/core": "^0.4.32",
|
58 |
"@sveltejs/adapter-node": "^2.0.0",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
"@xyflow/svelte": "^0.1.19",
|
60 |
"async": "^3.2.5",
|
61 |
"bits-ui": "^0.19.7",
|
|
|
1 |
{
|
2 |
"name": "open-webui",
|
3 |
+
"version": "0.4.3",
|
4 |
"private": true,
|
5 |
"scripts": {
|
6 |
"dev": "npm run pyodide:fetch && vite dev --host",
|
|
|
37 |
"postcss": "^8.4.31",
|
38 |
"prettier": "^3.3.3",
|
39 |
"prettier-plugin-svelte": "^3.2.6",
|
40 |
+
"sass-embedded": "^1.81.0",
|
41 |
"svelte": "^4.2.18",
|
42 |
"svelte-check": "^3.8.5",
|
43 |
"svelte-confetti": "^1.3.2",
|
|
|
57 |
"@mediapipe/tasks-vision": "^0.10.17",
|
58 |
"@pyscript/core": "^0.4.32",
|
59 |
"@sveltejs/adapter-node": "^2.0.0",
|
60 |
+
"@tiptap/core": "^2.10.0",
|
61 |
+
"@tiptap/extension-code-block-lowlight": "^2.10.0",
|
62 |
+
"@tiptap/extension-highlight": "^2.10.0",
|
63 |
+
"@tiptap/extension-placeholder": "^2.10.0",
|
64 |
+
"@tiptap/extension-typography": "^2.10.0",
|
65 |
+
"@tiptap/pm": "^2.10.0",
|
66 |
+
"@tiptap/starter-kit": "^2.10.0",
|
67 |
"@xyflow/svelte": "^0.1.19",
|
68 |
"async": "^3.2.5",
|
69 |
"bits-ui": "^0.19.7",
|
src/app.css
CHANGED
@@ -199,19 +199,86 @@ input[type='number'] {
|
|
199 |
}
|
200 |
|
201 |
.ProseMirror {
|
202 |
-
@apply h-full
|
203 |
}
|
204 |
|
205 |
.ProseMirror:focus {
|
206 |
outline: none;
|
207 |
}
|
208 |
|
209 |
-
.
|
210 |
content: attr(data-placeholder);
|
211 |
-
|
|
|
212 |
pointer-events: none;
|
|
|
|
|
213 |
|
214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
|
216 |
-
|
|
|
217 |
}
|
|
|
199 |
}
|
200 |
|
201 |
.ProseMirror {
|
202 |
+
@apply h-full min-h-fit max-h-full whitespace-pre-wrap;
|
203 |
}
|
204 |
|
205 |
.ProseMirror:focus {
|
206 |
outline: none;
|
207 |
}
|
208 |
|
209 |
+
.ProseMirror p.is-editor-empty:first-child::before {
|
210 |
content: attr(data-placeholder);
|
211 |
+
float: left;
|
212 |
+
color: #adb5bd;
|
213 |
pointer-events: none;
|
214 |
+
height: 0;
|
215 |
+
}
|
216 |
|
217 |
+
.tiptap > pre > code {
|
218 |
+
border-radius: 0.4rem;
|
219 |
+
font-size: 0.85rem;
|
220 |
+
padding: 0.25em 0.3em;
|
221 |
+
|
222 |
+
@apply dark:bg-gray-800 bg-gray-100;
|
223 |
+
}
|
224 |
+
|
225 |
+
.tiptap > pre {
|
226 |
+
border-radius: 0.5rem;
|
227 |
+
font-family: 'JetBrainsMono', monospace;
|
228 |
+
margin: 1.5rem 0;
|
229 |
+
padding: 0.75rem 1rem;
|
230 |
+
|
231 |
+
@apply dark:bg-gray-800 bg-gray-100;
|
232 |
+
}
|
233 |
+
|
234 |
+
/* Code styling */
|
235 |
+
.hljs-comment,
|
236 |
+
.hljs-quote {
|
237 |
+
color: #616161;
|
238 |
+
}
|
239 |
+
|
240 |
+
.hljs-variable,
|
241 |
+
.hljs-template-variable,
|
242 |
+
.hljs-attribute,
|
243 |
+
.hljs-tag,
|
244 |
+
.hljs-regexp,
|
245 |
+
.hljs-link,
|
246 |
+
.hljs-name,
|
247 |
+
.hljs-selector-id,
|
248 |
+
.hljs-selector-class {
|
249 |
+
color: #f98181;
|
250 |
+
}
|
251 |
+
|
252 |
+
.hljs-number,
|
253 |
+
.hljs-meta,
|
254 |
+
.hljs-built_in,
|
255 |
+
.hljs-builtin-name,
|
256 |
+
.hljs-literal,
|
257 |
+
.hljs-type,
|
258 |
+
.hljs-params {
|
259 |
+
color: #fbbc88;
|
260 |
+
}
|
261 |
+
|
262 |
+
.hljs-string,
|
263 |
+
.hljs-symbol,
|
264 |
+
.hljs-bullet {
|
265 |
+
color: #b9f18d;
|
266 |
+
}
|
267 |
+
|
268 |
+
.hljs-title,
|
269 |
+
.hljs-section {
|
270 |
+
color: #faf594;
|
271 |
+
}
|
272 |
+
|
273 |
+
.hljs-keyword,
|
274 |
+
.hljs-selector-tag {
|
275 |
+
color: #70cff8;
|
276 |
+
}
|
277 |
+
|
278 |
+
.hljs-emphasis {
|
279 |
+
font-style: italic;
|
280 |
+
}
|
281 |
|
282 |
+
.hljs-strong {
|
283 |
+
font-weight: 700;
|
284 |
}
|
src/lib/apis/streaming/index.ts
CHANGED
@@ -5,7 +5,7 @@ type TextStreamUpdate = {
|
|
5 |
done: boolean;
|
6 |
value: string;
|
7 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
8 |
-
|
9 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
10 |
selectedModelId?: any;
|
11 |
error?: any;
|
@@ -67,8 +67,8 @@ async function* openAIStreamToIterator(
|
|
67 |
break;
|
68 |
}
|
69 |
|
70 |
-
if (parsedData.
|
71 |
-
yield { done: false, value: '',
|
72 |
continue;
|
73 |
}
|
74 |
|
@@ -98,7 +98,7 @@ async function* streamLargeDeltasAsRandomChunks(
|
|
98 |
yield textStreamUpdate;
|
99 |
return;
|
100 |
}
|
101 |
-
if (textStreamUpdate.
|
102 |
yield textStreamUpdate;
|
103 |
continue;
|
104 |
}
|
|
|
5 |
done: boolean;
|
6 |
value: string;
|
7 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
8 |
+
sources?: any;
|
9 |
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
10 |
selectedModelId?: any;
|
11 |
error?: any;
|
|
|
67 |
break;
|
68 |
}
|
69 |
|
70 |
+
if (parsedData.sources) {
|
71 |
+
yield { done: false, value: '', sources: parsedData.sources };
|
72 |
continue;
|
73 |
}
|
74 |
|
|
|
98 |
yield textStreamUpdate;
|
99 |
return;
|
100 |
}
|
101 |
+
if (textStreamUpdate.sources) {
|
102 |
yield textStreamUpdate;
|
103 |
continue;
|
104 |
}
|
src/lib/components/admin/Settings/Connections/OpenAIConnection.svelte
CHANGED
@@ -60,7 +60,7 @@
|
|
60 |
/>
|
61 |
|
62 |
{#if pipeline}
|
63 |
-
<div class=" absolute top-
|
64 |
<Tooltip content="Pipelines">
|
65 |
<svg
|
66 |
xmlns="http://www.w3.org/2000/svg"
|
|
|
60 |
/>
|
61 |
|
62 |
{#if pipeline}
|
63 |
+
<div class=" absolute top-0.5 right-2.5">
|
64 |
<Tooltip content="Pipelines">
|
65 |
<svg
|
66 |
xmlns="http://www.w3.org/2000/svg"
|
src/lib/components/admin/Settings/Models.svelte
CHANGED
@@ -186,7 +186,7 @@
|
|
186 |
|
187 |
<div class=" my-2 mb-5" id="model-list">
|
188 |
{#if models.length > 0}
|
189 |
-
{#each filteredModels as model (model.id)}
|
190 |
<div
|
191 |
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-lg transition"
|
192 |
id="model-item-{model.id}"
|
|
|
186 |
|
187 |
<div class=" my-2 mb-5" id="model-list">
|
188 |
{#if models.length > 0}
|
189 |
+
{#each filteredModels as model, modelIdx (`${model.id}-${modelIdx}`)}
|
190 |
<div
|
191 |
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-lg transition"
|
192 |
id="model-item-{model.id}"
|
src/lib/components/admin/Settings/WebSearch.svelte
CHANGED
@@ -16,6 +16,7 @@
|
|
16 |
'searxng',
|
17 |
'google_pse',
|
18 |
'brave',
|
|
|
19 |
'serpstack',
|
20 |
'serper',
|
21 |
'serply',
|
@@ -151,6 +152,17 @@
|
|
151 |
bind:value={webConfig.search.brave_search_api_key}
|
152 |
/>
|
153 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
{:else if webConfig.search.engine === 'serpstack'}
|
155 |
<div>
|
156 |
<div class=" self-center text-xs font-medium mb-1">
|
|
|
16 |
'searxng',
|
17 |
'google_pse',
|
18 |
'brave',
|
19 |
+
'mojeek',
|
20 |
'serpstack',
|
21 |
'serper',
|
22 |
'serply',
|
|
|
152 |
bind:value={webConfig.search.brave_search_api_key}
|
153 |
/>
|
154 |
</div>
|
155 |
+
{:else if webConfig.search.engine === 'mojeek'}
|
156 |
+
<div>
|
157 |
+
<div class=" self-center text-xs font-medium mb-1">
|
158 |
+
{$i18n.t('Mojeek Search API Key')}
|
159 |
+
</div>
|
160 |
+
|
161 |
+
<SensitiveInput
|
162 |
+
placeholder={$i18n.t('Enter Mojeek Search API Key')}
|
163 |
+
bind:value={webConfig.search.mojeek_search_api_key}
|
164 |
+
/>
|
165 |
+
</div>
|
166 |
{:else if webConfig.search.engine === 'serpstack'}
|
167 |
<div>
|
168 |
<div class=" self-center text-xs font-medium mb-1">
|
src/lib/components/chat/Chat.svelte
CHANGED
@@ -216,7 +216,7 @@
|
|
216 |
} else {
|
217 |
message.statusHistory = [data];
|
218 |
}
|
219 |
-
} else if (type === '
|
220 |
if (data?.type === 'code_execution') {
|
221 |
// Code execution; update existing code execution by ID, or add new one.
|
222 |
if (!message?.code_executions) {
|
@@ -235,11 +235,11 @@
|
|
235 |
|
236 |
message.code_executions = message.code_executions;
|
237 |
} else {
|
238 |
-
// Regular
|
239 |
-
if (message?.
|
240 |
-
message.
|
241 |
} else {
|
242 |
-
message.
|
243 |
}
|
244 |
}
|
245 |
} else if (type === 'message') {
|
@@ -664,7 +664,7 @@
|
|
664 |
content: m.content,
|
665 |
info: m.info ? m.info : undefined,
|
666 |
timestamp: m.timestamp,
|
667 |
-
...(m.
|
668 |
})),
|
669 |
chat_id: chatId,
|
670 |
session_id: $socket?.id,
|
@@ -718,7 +718,7 @@
|
|
718 |
content: m.content,
|
719 |
info: m.info ? m.info : undefined,
|
720 |
timestamp: m.timestamp,
|
721 |
-
...(m.
|
722 |
})),
|
723 |
...(event ? { event: event } : {}),
|
724 |
chat_id: chatId,
|
@@ -1278,8 +1278,8 @@
|
|
1278 |
console.log(line);
|
1279 |
let data = JSON.parse(line);
|
1280 |
|
1281 |
-
if ('
|
1282 |
-
responseMessage.
|
1283 |
// Only remove status if it was initially set
|
1284 |
if (model?.info?.meta?.knowledge ?? false) {
|
1285 |
responseMessage.statusHistory = responseMessage.statusHistory.filter(
|
@@ -1632,7 +1632,7 @@
|
|
1632 |
const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks);
|
1633 |
|
1634 |
for await (const update of textStream) {
|
1635 |
-
const { value, done,
|
1636 |
if (error) {
|
1637 |
await handleOpenAIError(error, null, model, responseMessage);
|
1638 |
break;
|
@@ -1658,8 +1658,8 @@
|
|
1658 |
continue;
|
1659 |
}
|
1660 |
|
1661 |
-
if (
|
1662 |
-
responseMessage.
|
1663 |
// Only remove status if it was initially set
|
1664 |
if (model?.info?.meta?.knowledge ?? false) {
|
1665 |
responseMessage.statusHistory = responseMessage.statusHistory.filter(
|
@@ -1938,7 +1938,7 @@
|
|
1938 |
if (res && res.ok && res.body) {
|
1939 |
const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks);
|
1940 |
for await (const update of textStream) {
|
1941 |
-
const { value, done,
|
1942 |
if (error || done) {
|
1943 |
break;
|
1944 |
}
|
|
|
216 |
} else {
|
217 |
message.statusHistory = [data];
|
218 |
}
|
219 |
+
} else if (type === 'source') {
|
220 |
if (data?.type === 'code_execution') {
|
221 |
// Code execution; update existing code execution by ID, or add new one.
|
222 |
if (!message?.code_executions) {
|
|
|
235 |
|
236 |
message.code_executions = message.code_executions;
|
237 |
} else {
|
238 |
+
// Regular source.
|
239 |
+
if (message?.sources) {
|
240 |
+
message.sources.push(data);
|
241 |
} else {
|
242 |
+
message.sources = [data];
|
243 |
}
|
244 |
}
|
245 |
} else if (type === 'message') {
|
|
|
664 |
content: m.content,
|
665 |
info: m.info ? m.info : undefined,
|
666 |
timestamp: m.timestamp,
|
667 |
+
...(m.sources ? { sources: m.sources } : {})
|
668 |
})),
|
669 |
chat_id: chatId,
|
670 |
session_id: $socket?.id,
|
|
|
718 |
content: m.content,
|
719 |
info: m.info ? m.info : undefined,
|
720 |
timestamp: m.timestamp,
|
721 |
+
...(m.sources ? { sources: m.sources } : {})
|
722 |
})),
|
723 |
...(event ? { event: event } : {}),
|
724 |
chat_id: chatId,
|
|
|
1278 |
console.log(line);
|
1279 |
let data = JSON.parse(line);
|
1280 |
|
1281 |
+
if ('sources' in data) {
|
1282 |
+
responseMessage.sources = data.sources;
|
1283 |
// Only remove status if it was initially set
|
1284 |
if (model?.info?.meta?.knowledge ?? false) {
|
1285 |
responseMessage.statusHistory = responseMessage.statusHistory.filter(
|
|
|
1632 |
const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks);
|
1633 |
|
1634 |
for await (const update of textStream) {
|
1635 |
+
const { value, done, sources, selectedModelId, error, usage } = update;
|
1636 |
if (error) {
|
1637 |
await handleOpenAIError(error, null, model, responseMessage);
|
1638 |
break;
|
|
|
1658 |
continue;
|
1659 |
}
|
1660 |
|
1661 |
+
if (sources) {
|
1662 |
+
responseMessage.sources = sources;
|
1663 |
// Only remove status if it was initially set
|
1664 |
if (model?.info?.meta?.knowledge ?? false) {
|
1665 |
responseMessage.statusHistory = responseMessage.statusHistory.filter(
|
|
|
1938 |
if (res && res.ok && res.body) {
|
1939 |
const textStream = await createOpenAITextStream(res.body, $settings.splitLargeChunks);
|
1940 |
for await (const update of textStream) {
|
1941 |
+
const { value, done, sources, error, usage } = update;
|
1942 |
if (error || done) {
|
1943 |
break;
|
1944 |
}
|
src/lib/components/chat/MessageInput.svelte
CHANGED
@@ -75,14 +75,6 @@
|
|
75 |
(model) => $models.find((m) => m.id === model)?.info?.meta?.capabilities?.vision ?? true
|
76 |
);
|
77 |
|
78 |
-
$: if (prompt) {
|
79 |
-
if (chatInputContainerElement) {
|
80 |
-
chatInputContainerElement.style.height = '';
|
81 |
-
chatInputContainerElement.style.height =
|
82 |
-
Math.min(chatInputContainerElement.scrollHeight, 200) + 'px';
|
83 |
-
}
|
84 |
-
}
|
85 |
-
|
86 |
const scrollToBottom = () => {
|
87 |
const element = document.getElementById('messages-container');
|
88 |
element.scrollTo({
|
@@ -585,54 +577,47 @@
|
|
585 |
|
586 |
{#if $settings?.richTextInput ?? true}
|
587 |
<div
|
588 |
-
|
589 |
-
id="chat-input-container"
|
590 |
-
class="scrollbar-hidden text-left bg-gray-50 dark:bg-gray-850 dark:text-gray-100 outline-none w-full py-2.5 px-1 rounded-xl resize-none h-[48px] overflow-auto"
|
591 |
>
|
592 |
<RichTextInput
|
593 |
bind:this={chatInputElement}
|
594 |
id="chat-input"
|
595 |
-
|
596 |
-
placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
|
597 |
-
largeTextAsFile={$settings?.largeTextAsFile ?? false}
|
598 |
-
bind:value={prompt}
|
599 |
shiftEnter={!$mobile ||
|
600 |
!(
|
601 |
'ontouchstart' in window ||
|
602 |
navigator.maxTouchPoints > 0 ||
|
603 |
navigator.msMaxTouchPoints > 0
|
604 |
)}
|
|
|
|
|
|
|
605 |
on:enter={async (e) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
606 |
if (prompt !== '') {
|
607 |
dispatch('submit', prompt);
|
608 |
}
|
609 |
}}
|
610 |
-
on:input={async (e) => {
|
611 |
-
if (chatInputContainerElement) {
|
612 |
-
chatInputContainerElement.style.height = '';
|
613 |
-
chatInputContainerElement.style.height =
|
614 |
-
Math.min(chatInputContainerElement.scrollHeight, 200) + 'px';
|
615 |
-
}
|
616 |
-
}}
|
617 |
-
on:focus={async (e) => {
|
618 |
-
if (chatInputContainerElement) {
|
619 |
-
chatInputContainerElement.style.height = '';
|
620 |
-
chatInputContainerElement.style.height =
|
621 |
-
Math.min(chatInputContainerElement.scrollHeight, 200) + 'px';
|
622 |
-
}
|
623 |
-
}}
|
624 |
on:keypress={(e) => {
|
625 |
e = e.detail.event;
|
626 |
}}
|
627 |
on:keydown={async (e) => {
|
628 |
e = e.detail.event;
|
629 |
|
630 |
-
if (chatInputContainerElement) {
|
631 |
-
chatInputContainerElement.style.height = '';
|
632 |
-
chatInputContainerElement.style.height =
|
633 |
-
Math.min(chatInputContainerElement.scrollHeight, 200) + 'px';
|
634 |
-
}
|
635 |
-
|
636 |
const isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac
|
637 |
const commandsContainerElement =
|
638 |
document.getElementById('commands-container');
|
@@ -692,22 +677,6 @@
|
|
692 |
commandOptionButton.scrollIntoView({ block: 'center' });
|
693 |
}
|
694 |
|
695 |
-
if (commandsContainerElement && e.key === 'Enter') {
|
696 |
-
e.preventDefault();
|
697 |
-
|
698 |
-
const commandOptionButton = [
|
699 |
-
...document.getElementsByClassName('selected-command-option-button')
|
700 |
-
]?.at(-1);
|
701 |
-
|
702 |
-
if (e.shiftKey) {
|
703 |
-
prompt = `${prompt}\n`;
|
704 |
-
} else if (commandOptionButton) {
|
705 |
-
commandOptionButton?.click();
|
706 |
-
} else {
|
707 |
-
document.getElementById('send-message-button')?.click();
|
708 |
-
}
|
709 |
-
}
|
710 |
-
|
711 |
if (commandsContainerElement && e.key === 'Tab') {
|
712 |
e.preventDefault();
|
713 |
|
|
|
75 |
(model) => $models.find((m) => m.id === model)?.info?.meta?.capabilities?.vision ?? true
|
76 |
);
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
const scrollToBottom = () => {
|
79 |
const element = document.getElementById('messages-container');
|
80 |
element.scrollTo({
|
|
|
577 |
|
578 |
{#if $settings?.richTextInput ?? true}
|
579 |
<div
|
580 |
+
class="scrollbar-hidden text-left bg-gray-50 dark:bg-gray-850 dark:text-gray-100 outline-none w-full py-2.5 px-1 rounded-xl resize-none h-fit max-h-60 overflow-auto"
|
|
|
|
|
581 |
>
|
582 |
<RichTextInput
|
583 |
bind:this={chatInputElement}
|
584 |
id="chat-input"
|
585 |
+
messageInput={true}
|
|
|
|
|
|
|
586 |
shiftEnter={!$mobile ||
|
587 |
!(
|
588 |
'ontouchstart' in window ||
|
589 |
navigator.maxTouchPoints > 0 ||
|
590 |
navigator.msMaxTouchPoints > 0
|
591 |
)}
|
592 |
+
placeholder={placeholder ? placeholder : $i18n.t('Send a Message')}
|
593 |
+
largeTextAsFile={$settings?.largeTextAsFile ?? false}
|
594 |
+
bind:value={prompt}
|
595 |
on:enter={async (e) => {
|
596 |
+
const commandsContainerElement =
|
597 |
+
document.getElementById('commands-container');
|
598 |
+
if (commandsContainerElement) {
|
599 |
+
e.preventDefault();
|
600 |
+
|
601 |
+
const commandOptionButton = [
|
602 |
+
...document.getElementsByClassName('selected-command-option-button')
|
603 |
+
]?.at(-1);
|
604 |
+
|
605 |
+
if (commandOptionButton) {
|
606 |
+
commandOptionButton?.click();
|
607 |
+
return;
|
608 |
+
}
|
609 |
+
}
|
610 |
+
|
611 |
if (prompt !== '') {
|
612 |
dispatch('submit', prompt);
|
613 |
}
|
614 |
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
615 |
on:keypress={(e) => {
|
616 |
e = e.detail.event;
|
617 |
}}
|
618 |
on:keydown={async (e) => {
|
619 |
e = e.detail.event;
|
620 |
|
|
|
|
|
|
|
|
|
|
|
|
|
621 |
const isCtrlPressed = e.ctrlKey || e.metaKey; // metaKey is for Cmd key on Mac
|
622 |
const commandsContainerElement =
|
623 |
document.getElementById('commands-container');
|
|
|
677 |
commandOptionButton.scrollIntoView({ block: 'center' });
|
678 |
}
|
679 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
680 |
if (commandsContainerElement && e.key === 'Tab') {
|
681 |
e.preventDefault();
|
682 |
|
src/lib/components/chat/Messages/Citations.svelte
CHANGED
@@ -7,9 +7,9 @@
|
|
7 |
|
8 |
const i18n = getContext('i18n');
|
9 |
|
10 |
-
export let
|
11 |
|
12 |
-
let
|
13 |
let showPercentage = false;
|
14 |
let showRelevance = true;
|
15 |
|
@@ -17,8 +17,8 @@
|
|
17 |
let selectedCitation: any = null;
|
18 |
let isCollapsibleOpen = false;
|
19 |
|
20 |
-
function calculateShowRelevance(
|
21 |
-
const distances =
|
22 |
const inRange = distances.filter((d) => d !== undefined && d >= -1 && d <= 1).length;
|
23 |
const outOfRange = distances.filter((d) => d !== undefined && (d < -1 || d > 1)).length;
|
24 |
|
@@ -36,25 +36,31 @@
|
|
36 |
return true;
|
37 |
}
|
38 |
|
39 |
-
function shouldShowPercentage(
|
40 |
-
const distances =
|
41 |
return distances.every((d) => d !== undefined && d >= -1 && d <= 1);
|
42 |
}
|
43 |
|
44 |
$: {
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
const id = metadata?.source ?? 'N/A';
|
50 |
-
let
|
51 |
|
52 |
if (metadata?.name) {
|
53 |
-
|
54 |
}
|
55 |
|
56 |
if (id.startsWith('http://') || id.startsWith('https://')) {
|
57 |
-
|
58 |
}
|
59 |
|
60 |
const existingSource = acc.find((item) => item.id === id);
|
@@ -66,7 +72,7 @@
|
|
66 |
} else {
|
67 |
acc.push({
|
68 |
id: id,
|
69 |
-
source:
|
70 |
document: [document],
|
71 |
metadata: metadata ? [metadata] : [],
|
72 |
distances: distance !== undefined ? [distance] : undefined
|
@@ -76,8 +82,8 @@
|
|
76 |
return acc;
|
77 |
}, []);
|
78 |
|
79 |
-
showRelevance = calculateShowRelevance(
|
80 |
-
showPercentage = shouldShowPercentage(
|
81 |
}
|
82 |
</script>
|
83 |
|
@@ -88,24 +94,27 @@
|
|
88 |
{showRelevance}
|
89 |
/>
|
90 |
|
91 |
-
{#if
|
92 |
<div class=" py-0.5 -mx-0.5 w-full flex gap-1 items-center flex-wrap">
|
93 |
-
{#if
|
94 |
<div class="flex text-xs font-medium">
|
95 |
-
{#each
|
96 |
<button
|
97 |
-
|
|
|
98 |
on:click={() => {
|
99 |
showCitationModal = true;
|
100 |
selectedCitation = citation;
|
101 |
}}
|
102 |
>
|
103 |
-
{#if
|
104 |
<div class="bg-gray-50 dark:bg-gray-800 rounded-full size-4">
|
105 |
{idx + 1}
|
106 |
</div>
|
107 |
{/if}
|
108 |
-
<div
|
|
|
|
|
109 |
{citation.source.name}
|
110 |
</div>
|
111 |
</button>
|
@@ -120,7 +129,7 @@
|
|
120 |
<span class="whitespace-nowrap hidden sm:inline">{$i18n.t('References from')}</span>
|
121 |
<div class="flex items-center">
|
122 |
<div class="flex text-xs font-medium items-center">
|
123 |
-
{#each
|
124 |
<button
|
125 |
class="no-toggle outline-none flex dark:text-gray-300 p-1 bg-gray-50 hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 transition rounded-xl max-w-96"
|
126 |
on:click={() => {
|
@@ -131,7 +140,7 @@
|
|
131 |
e.stopPropagation();
|
132 |
}}
|
133 |
>
|
134 |
-
{#if
|
135 |
<div class="bg-gray-50 dark:bg-gray-800 rounded-full size-4">
|
136 |
{idx + 1}
|
137 |
</div>
|
@@ -145,7 +154,7 @@
|
|
145 |
</div>
|
146 |
<div class="flex items-center gap-1 whitespace-nowrap">
|
147 |
<span class="hidden sm:inline">{$i18n.t('and')}</span>
|
148 |
-
{
|
149 |
<span>{$i18n.t('more')}</span>
|
150 |
</div>
|
151 |
</div>
|
@@ -159,7 +168,7 @@
|
|
159 |
</div>
|
160 |
<div slot="content">
|
161 |
<div class="flex text-xs font-medium">
|
162 |
-
{#each
|
163 |
<button
|
164 |
class="no-toggle outline-none flex dark:text-gray-300 p-1 bg-gray-50 hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 transition rounded-xl max-w-96"
|
165 |
on:click={() => {
|
@@ -167,7 +176,7 @@
|
|
167 |
selectedCitation = citation;
|
168 |
}}
|
169 |
>
|
170 |
-
{#if
|
171 |
<div class="bg-gray-50 dark:bg-gray-800 rounded-full size-4">
|
172 |
{idx + 1}
|
173 |
</div>
|
|
|
7 |
|
8 |
const i18n = getContext('i18n');
|
9 |
|
10 |
+
export let sources = [];
|
11 |
|
12 |
+
let citations = [];
|
13 |
let showPercentage = false;
|
14 |
let showRelevance = true;
|
15 |
|
|
|
17 |
let selectedCitation: any = null;
|
18 |
let isCollapsibleOpen = false;
|
19 |
|
20 |
+
function calculateShowRelevance(sources: any[]) {
|
21 |
+
const distances = sources.flatMap((citation) => citation.distances ?? []);
|
22 |
const inRange = distances.filter((d) => d !== undefined && d >= -1 && d <= 1).length;
|
23 |
const outOfRange = distances.filter((d) => d !== undefined && (d < -1 || d > 1)).length;
|
24 |
|
|
|
36 |
return true;
|
37 |
}
|
38 |
|
39 |
+
function shouldShowPercentage(sources: any[]) {
|
40 |
+
const distances = sources.flatMap((citation) => citation.distances ?? []);
|
41 |
return distances.every((d) => d !== undefined && d >= -1 && d <= 1);
|
42 |
}
|
43 |
|
44 |
$: {
|
45 |
+
citations = sources.reduce((acc, source) => {
|
46 |
+
if (Object.keys(source).length === 0) {
|
47 |
+
return acc;
|
48 |
+
}
|
49 |
+
|
50 |
+
source.document.forEach((document, index) => {
|
51 |
+
const metadata = source.metadata?.[index];
|
52 |
+
const distance = source.distances?.[index];
|
53 |
+
|
54 |
+
// Within the same citation there could be multiple documents
|
55 |
const id = metadata?.source ?? 'N/A';
|
56 |
+
let _source = source?.source;
|
57 |
|
58 |
if (metadata?.name) {
|
59 |
+
_source = { ..._source, name: metadata.name };
|
60 |
}
|
61 |
|
62 |
if (id.startsWith('http://') || id.startsWith('https://')) {
|
63 |
+
_source = { ..._source, name: id, url: id };
|
64 |
}
|
65 |
|
66 |
const existingSource = acc.find((item) => item.id === id);
|
|
|
72 |
} else {
|
73 |
acc.push({
|
74 |
id: id,
|
75 |
+
source: _source,
|
76 |
document: [document],
|
77 |
metadata: metadata ? [metadata] : [],
|
78 |
distances: distance !== undefined ? [distance] : undefined
|
|
|
82 |
return acc;
|
83 |
}, []);
|
84 |
|
85 |
+
showRelevance = calculateShowRelevance(citations);
|
86 |
+
showPercentage = shouldShowPercentage(citations);
|
87 |
}
|
88 |
</script>
|
89 |
|
|
|
94 |
{showRelevance}
|
95 |
/>
|
96 |
|
97 |
+
{#if citations.length > 0}
|
98 |
<div class=" py-0.5 -mx-0.5 w-full flex gap-1 items-center flex-wrap">
|
99 |
+
{#if citations.length <= 3}
|
100 |
<div class="flex text-xs font-medium">
|
101 |
+
{#each citations as citation, idx}
|
102 |
<button
|
103 |
+
id={`source-${citation.source.name}`}
|
104 |
+
class="no-toggle outline-none flex dark:text-gray-300 p-1 bg-white dark:bg-gray-900 rounded-xl max-w-96"
|
105 |
on:click={() => {
|
106 |
showCitationModal = true;
|
107 |
selectedCitation = citation;
|
108 |
}}
|
109 |
>
|
110 |
+
{#if citations.every((c) => c.distances !== undefined)}
|
111 |
<div class="bg-gray-50 dark:bg-gray-800 rounded-full size-4">
|
112 |
{idx + 1}
|
113 |
</div>
|
114 |
{/if}
|
115 |
+
<div
|
116 |
+
class="flex-1 mx-1 line-clamp-1 text-black/60 hover:text-black dark:text-white/60 dark:hover:text-white transition"
|
117 |
+
>
|
118 |
{citation.source.name}
|
119 |
</div>
|
120 |
</button>
|
|
|
129 |
<span class="whitespace-nowrap hidden sm:inline">{$i18n.t('References from')}</span>
|
130 |
<div class="flex items-center">
|
131 |
<div class="flex text-xs font-medium items-center">
|
132 |
+
{#each citations.slice(0, 2) as citation, idx}
|
133 |
<button
|
134 |
class="no-toggle outline-none flex dark:text-gray-300 p-1 bg-gray-50 hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 transition rounded-xl max-w-96"
|
135 |
on:click={() => {
|
|
|
140 |
e.stopPropagation();
|
141 |
}}
|
142 |
>
|
143 |
+
{#if citations.every((c) => c.distances !== undefined)}
|
144 |
<div class="bg-gray-50 dark:bg-gray-800 rounded-full size-4">
|
145 |
{idx + 1}
|
146 |
</div>
|
|
|
154 |
</div>
|
155 |
<div class="flex items-center gap-1 whitespace-nowrap">
|
156 |
<span class="hidden sm:inline">{$i18n.t('and')}</span>
|
157 |
+
{citations.length - 2}
|
158 |
<span>{$i18n.t('more')}</span>
|
159 |
</div>
|
160 |
</div>
|
|
|
168 |
</div>
|
169 |
<div slot="content">
|
170 |
<div class="flex text-xs font-medium">
|
171 |
+
{#each citations as citation, idx}
|
172 |
<button
|
173 |
class="no-toggle outline-none flex dark:text-gray-300 p-1 bg-gray-50 hover:bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-850 transition rounded-xl max-w-96"
|
174 |
on:click={() => {
|
|
|
176 |
selectedCitation = citation;
|
177 |
}}
|
178 |
>
|
179 |
+
{#if citations.every((c) => c.distances !== undefined)}
|
180 |
<div class="bg-gray-50 dark:bg-gray-800 rounded-full size-4">
|
181 |
{idx + 1}
|
182 |
</div>
|
src/lib/components/chat/Messages/ContentRenderer.svelte
CHANGED
@@ -7,13 +7,16 @@
|
|
7 |
import LightBlub from '$lib/components/icons/LightBlub.svelte';
|
8 |
import { chatId, mobile, showArtifacts, showControls, showOverview } from '$lib/stores';
|
9 |
import ChatBubble from '$lib/components/icons/ChatBubble.svelte';
|
|
|
10 |
|
11 |
export let id;
|
12 |
export let content;
|
13 |
export let model = null;
|
|
|
14 |
|
15 |
export let save = false;
|
16 |
export let floatingButtons = true;
|
|
|
17 |
|
18 |
let contentContainerElement;
|
19 |
let buttonsContainerElement;
|
@@ -129,6 +132,32 @@
|
|
129 |
{content}
|
130 |
{model}
|
131 |
{save}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
on:update={(e) => {
|
133 |
dispatch('update', e.detail);
|
134 |
}}
|
|
|
7 |
import LightBlub from '$lib/components/icons/LightBlub.svelte';
|
8 |
import { chatId, mobile, showArtifacts, showControls, showOverview } from '$lib/stores';
|
9 |
import ChatBubble from '$lib/components/icons/ChatBubble.svelte';
|
10 |
+
import { stringify } from 'postcss';
|
11 |
|
12 |
export let id;
|
13 |
export let content;
|
14 |
export let model = null;
|
15 |
+
export let sources = null;
|
16 |
|
17 |
export let save = false;
|
18 |
export let floatingButtons = true;
|
19 |
+
export let onSourceClick = () => {};
|
20 |
|
21 |
let contentContainerElement;
|
22 |
let buttonsContainerElement;
|
|
|
132 |
{content}
|
133 |
{model}
|
134 |
{save}
|
135 |
+
sourceIds={(sources ?? []).reduce((acc, s) => {
|
136 |
+
let ids = [];
|
137 |
+
s.document.forEach((document, index) => {
|
138 |
+
const metadata = s.metadata?.[index];
|
139 |
+
const id = metadata?.source ?? 'N/A';
|
140 |
+
|
141 |
+
if (metadata?.name) {
|
142 |
+
ids.push(metadata.name);
|
143 |
+
return ids;
|
144 |
+
}
|
145 |
+
|
146 |
+
if (id.startsWith('http://') || id.startsWith('https://')) {
|
147 |
+
ids.push(id);
|
148 |
+
} else {
|
149 |
+
ids.push(s?.source?.name ?? id);
|
150 |
+
}
|
151 |
+
|
152 |
+
return ids;
|
153 |
+
});
|
154 |
+
|
155 |
+
acc = [...acc, ...ids];
|
156 |
+
|
157 |
+
// remove duplicates
|
158 |
+
return acc.filter((item, index) => acc.indexOf(item) === index);
|
159 |
+
}, [])}
|
160 |
+
{onSourceClick}
|
161 |
on:update={(e) => {
|
162 |
dispatch('update', e.detail);
|
163 |
}}
|
src/lib/components/chat/Messages/Markdown.svelte
CHANGED
@@ -16,6 +16,9 @@
|
|
16 |
export let model = null;
|
17 |
export let save = false;
|
18 |
|
|
|
|
|
|
|
19 |
let tokens = [];
|
20 |
|
21 |
const options = {
|
@@ -28,7 +31,7 @@
|
|
28 |
$: (async () => {
|
29 |
if (content) {
|
30 |
tokens = marked.lexer(
|
31 |
-
replaceTokens(processResponseContent(content), model?.name, $user?.name)
|
32 |
);
|
33 |
}
|
34 |
})();
|
@@ -39,6 +42,7 @@
|
|
39 |
{tokens}
|
40 |
{id}
|
41 |
{save}
|
|
|
42 |
on:update={(e) => {
|
43 |
dispatch('update', e.detail);
|
44 |
}}
|
|
|
16 |
export let model = null;
|
17 |
export let save = false;
|
18 |
|
19 |
+
export let sourceIds = [];
|
20 |
+
export let onSourceClick = () => {};
|
21 |
+
|
22 |
let tokens = [];
|
23 |
|
24 |
const options = {
|
|
|
31 |
$: (async () => {
|
32 |
if (content) {
|
33 |
tokens = marked.lexer(
|
34 |
+
replaceTokens(processResponseContent(content), sourceIds, model?.name, $user?.name)
|
35 |
);
|
36 |
}
|
37 |
})();
|
|
|
42 |
{tokens}
|
43 |
{id}
|
44 |
{save}
|
45 |
+
{onSourceClick}
|
46 |
on:update={(e) => {
|
47 |
dispatch('update', e.detail);
|
48 |
}}
|
src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte
CHANGED
@@ -12,9 +12,11 @@
|
|
12 |
|
13 |
import Image from '$lib/components/common/Image.svelte';
|
14 |
import KatexRenderer from './KatexRenderer.svelte';
|
|
|
15 |
|
16 |
export let id: string;
|
17 |
export let tokens: Token[];
|
|
|
18 |
</script>
|
19 |
|
20 |
{#each tokens as token}
|
@@ -26,13 +28,15 @@
|
|
26 |
{@html html}
|
27 |
{:else if token.text.includes(`<iframe src="${WEBUI_BASE_URL}/api/v1/files/`)}
|
28 |
{@html `${token.text}`}
|
|
|
|
|
29 |
{:else}
|
30 |
{token.text}
|
31 |
{/if}
|
32 |
{:else if token.type === 'link'}
|
33 |
{#if token.tokens}
|
34 |
<a href={token.href} target="_blank" rel="nofollow" title={token.title}>
|
35 |
-
<svelte:self id={`${id}-a`} tokens={token.tokens} />
|
36 |
</a>
|
37 |
{:else}
|
38 |
<a href={token.href} target="_blank" rel="nofollow" title={token.title}>{token.text}</a>
|
@@ -41,11 +45,11 @@
|
|
41 |
<Image src={token.href} alt={token.text} />
|
42 |
{:else if token.type === 'strong'}
|
43 |
<strong>
|
44 |
-
<svelte:self id={`${id}-strong`} tokens={token.tokens} />
|
45 |
</strong>
|
46 |
{:else if token.type === 'em'}
|
47 |
<em>
|
48 |
-
<svelte:self id={`${id}-em`} tokens={token.tokens} />
|
49 |
</em>
|
50 |
{:else if token.type === 'codespan'}
|
51 |
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
@@ -61,7 +65,7 @@
|
|
61 |
<br />
|
62 |
{:else if token.type === 'del'}
|
63 |
<del>
|
64 |
-
<svelte:self id={`${id}-del`} tokens={token.tokens} />
|
65 |
</del>
|
66 |
{:else if token.type === 'inlineKatex'}
|
67 |
{#if token.text}
|
|
|
12 |
|
13 |
import Image from '$lib/components/common/Image.svelte';
|
14 |
import KatexRenderer from './KatexRenderer.svelte';
|
15 |
+
import Source from './Source.svelte';
|
16 |
|
17 |
export let id: string;
|
18 |
export let tokens: Token[];
|
19 |
+
export let onSourceClick: Function = () => {};
|
20 |
</script>
|
21 |
|
22 |
{#each tokens as token}
|
|
|
28 |
{@html html}
|
29 |
{:else if token.text.includes(`<iframe src="${WEBUI_BASE_URL}/api/v1/files/`)}
|
30 |
{@html `${token.text}`}
|
31 |
+
{:else if token.text.includes(`<source_id`)}
|
32 |
+
<Source {token} onClick={onSourceClick} />
|
33 |
{:else}
|
34 |
{token.text}
|
35 |
{/if}
|
36 |
{:else if token.type === 'link'}
|
37 |
{#if token.tokens}
|
38 |
<a href={token.href} target="_blank" rel="nofollow" title={token.title}>
|
39 |
+
<svelte:self id={`${id}-a`} tokens={token.tokens} {onSourceClick} />
|
40 |
</a>
|
41 |
{:else}
|
42 |
<a href={token.href} target="_blank" rel="nofollow" title={token.title}>{token.text}</a>
|
|
|
45 |
<Image src={token.href} alt={token.text} />
|
46 |
{:else if token.type === 'strong'}
|
47 |
<strong>
|
48 |
+
<svelte:self id={`${id}-strong`} tokens={token.tokens} {onSourceClick} />
|
49 |
</strong>
|
50 |
{:else if token.type === 'em'}
|
51 |
<em>
|
52 |
+
<svelte:self id={`${id}-em`} tokens={token.tokens} {onSourceClick} />
|
53 |
</em>
|
54 |
{:else if token.type === 'codespan'}
|
55 |
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
|
65 |
<br />
|
66 |
{:else if token.type === 'del'}
|
67 |
<del>
|
68 |
+
<svelte:self id={`${id}-del`} tokens={token.tokens} {onSourceClick} />
|
69 |
</del>
|
70 |
{:else if token.type === 'inlineKatex'}
|
71 |
{#if token.text}
|
src/lib/components/chat/Messages/Markdown/MarkdownTokens.svelte
CHANGED
@@ -25,6 +25,7 @@
|
|
25 |
export let top = true;
|
26 |
|
27 |
export let save = false;
|
|
|
28 |
|
29 |
const headerComponent = (depth: number) => {
|
30 |
return 'h' + depth;
|
@@ -62,7 +63,7 @@
|
|
62 |
<hr />
|
63 |
{:else if token.type === 'heading'}
|
64 |
<svelte:element this={headerComponent(token.depth)}>
|
65 |
-
<MarkdownInlineTokens id={`${id}-${tokenIdx}-h`} tokens={token.tokens} />
|
66 |
</svelte:element>
|
67 |
{:else if token.type === 'code'}
|
68 |
{#if token.raw.includes('```')}
|
@@ -108,6 +109,7 @@
|
|
108 |
<MarkdownInlineTokens
|
109 |
id={`${id}-${tokenIdx}-header-${headerIdx}`}
|
110 |
tokens={header.tokens}
|
|
|
111 |
/>
|
112 |
</div>
|
113 |
</th>
|
@@ -126,6 +128,7 @@
|
|
126 |
<MarkdownInlineTokens
|
127 |
id={`${id}-${tokenIdx}-row-${rowIdx}-${cellIdx}`}
|
128 |
tokens={cell.tokens}
|
|
|
129 |
/>
|
130 |
</div>
|
131 |
</td>
|
@@ -205,19 +208,27 @@
|
|
205 |
></iframe>
|
206 |
{:else if token.type === 'paragraph'}
|
207 |
<p>
|
208 |
-
<MarkdownInlineTokens
|
|
|
|
|
|
|
|
|
209 |
</p>
|
210 |
{:else if token.type === 'text'}
|
211 |
{#if top}
|
212 |
<p>
|
213 |
{#if token.tokens}
|
214 |
-
<MarkdownInlineTokens id={`${id}-${tokenIdx}-t`} tokens={token.tokens} />
|
215 |
{:else}
|
216 |
{unescapeHtml(token.text)}
|
217 |
{/if}
|
218 |
</p>
|
219 |
{:else if token.tokens}
|
220 |
-
<MarkdownInlineTokens
|
|
|
|
|
|
|
|
|
221 |
{:else}
|
222 |
{unescapeHtml(token.text)}
|
223 |
{/if}
|
|
|
25 |
export let top = true;
|
26 |
|
27 |
export let save = false;
|
28 |
+
export let onSourceClick: Function = () => {};
|
29 |
|
30 |
const headerComponent = (depth: number) => {
|
31 |
return 'h' + depth;
|
|
|
63 |
<hr />
|
64 |
{:else if token.type === 'heading'}
|
65 |
<svelte:element this={headerComponent(token.depth)}>
|
66 |
+
<MarkdownInlineTokens id={`${id}-${tokenIdx}-h`} tokens={token.tokens} {onSourceClick} />
|
67 |
</svelte:element>
|
68 |
{:else if token.type === 'code'}
|
69 |
{#if token.raw.includes('```')}
|
|
|
109 |
<MarkdownInlineTokens
|
110 |
id={`${id}-${tokenIdx}-header-${headerIdx}`}
|
111 |
tokens={header.tokens}
|
112 |
+
{onSourceClick}
|
113 |
/>
|
114 |
</div>
|
115 |
</th>
|
|
|
128 |
<MarkdownInlineTokens
|
129 |
id={`${id}-${tokenIdx}-row-${rowIdx}-${cellIdx}`}
|
130 |
tokens={cell.tokens}
|
131 |
+
{onSourceClick}
|
132 |
/>
|
133 |
</div>
|
134 |
</td>
|
|
|
208 |
></iframe>
|
209 |
{:else if token.type === 'paragraph'}
|
210 |
<p>
|
211 |
+
<MarkdownInlineTokens
|
212 |
+
id={`${id}-${tokenIdx}-p`}
|
213 |
+
tokens={token.tokens ?? []}
|
214 |
+
{onSourceClick}
|
215 |
+
/>
|
216 |
</p>
|
217 |
{:else if token.type === 'text'}
|
218 |
{#if top}
|
219 |
<p>
|
220 |
{#if token.tokens}
|
221 |
+
<MarkdownInlineTokens id={`${id}-${tokenIdx}-t`} tokens={token.tokens} {onSourceClick} />
|
222 |
{:else}
|
223 |
{unescapeHtml(token.text)}
|
224 |
{/if}
|
225 |
</p>
|
226 |
{:else if token.tokens}
|
227 |
+
<MarkdownInlineTokens
|
228 |
+
id={`${id}-${tokenIdx}-p`}
|
229 |
+
tokens={token.tokens ?? []}
|
230 |
+
{onSourceClick}
|
231 |
+
/>
|
232 |
{:else}
|
233 |
{unescapeHtml(token.text)}
|
234 |
{/if}
|
src/lib/components/chat/Messages/Markdown/Source.svelte
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
export let token;
|
3 |
+
export let onClick: Function = () => {};
|
4 |
+
|
5 |
+
let id = '';
|
6 |
+
function extractDataAttribute(input) {
|
7 |
+
// Use a regular expression to extract the value of the `data` attribute
|
8 |
+
const match = input.match(/data="([^"]*)"/);
|
9 |
+
// Check if a match was found and return the first captured group
|
10 |
+
return match ? match[1] : null;
|
11 |
+
}
|
12 |
+
|
13 |
+
$: id = extractDataAttribute(token.text);
|
14 |
+
</script>
|
15 |
+
|
16 |
+
<button
|
17 |
+
class="text-xs font-medium w-fit translate-y-[2px] px-2 py-0.5 dark:bg-white/5 dark:text-white/60 dark:hover:text-white bg-gray-50 text-black/60 hover:text-black transition rounded-lg"
|
18 |
+
on:click={() => {
|
19 |
+
onClick(id);
|
20 |
+
}}
|
21 |
+
>
|
22 |
+
<span class="line-clamp-1">
|
23 |
+
{id}
|
24 |
+
</span>
|
25 |
+
</button>
|
src/lib/components/chat/Messages/RateComment.svelte
CHANGED
@@ -136,7 +136,7 @@
|
|
136 |
class="size-7 text-sm border border-gray-50 dark:border-gray-850 hover:bg-gray-50 dark:hover:bg-gray-850 {detailedRating ===
|
137 |
rating
|
138 |
? 'bg-gray-100 dark:bg-gray-800'
|
139 |
-
: ''} transition rounded-full disabled:cursor-not-allowed disabled:bg-white disabled:dark:bg-gray-900"
|
140 |
on:click={() => {
|
141 |
detailedRating = rating;
|
142 |
}}
|
|
|
136 |
class="size-7 text-sm border border-gray-50 dark:border-gray-850 hover:bg-gray-50 dark:hover:bg-gray-850 {detailedRating ===
|
137 |
rating
|
138 |
? 'bg-gray-100 dark:bg-gray-800'
|
139 |
+
: ''} transition rounded-full disabled:cursor-not-allowed disabled:text-gray-500 disabled:bg-white disabled:dark:bg-gray-900"
|
140 |
on:click={() => {
|
141 |
detailedRating = rating;
|
142 |
}}
|
src/lib/components/chat/Messages/ResponseMessage.svelte
CHANGED
@@ -64,7 +64,7 @@
|
|
64 |
};
|
65 |
done: boolean;
|
66 |
error?: boolean | { content: string };
|
67 |
-
|
68 |
code_executions?: {
|
69 |
uuid: string;
|
70 |
name: string;
|
@@ -621,9 +621,18 @@
|
|
621 |
<ContentRenderer
|
622 |
id={message.id}
|
623 |
content={message.content}
|
|
|
624 |
floatingButtons={message?.done}
|
625 |
save={!readOnly}
|
626 |
{model}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
627 |
on:update={(e) => {
|
628 |
const { raw, oldContent, newContent } = e.detail;
|
629 |
|
@@ -653,8 +662,8 @@
|
|
653 |
<Error content={message?.error?.content ?? message.content} />
|
654 |
{/if}
|
655 |
|
656 |
-
{#if message
|
657 |
-
<Citations
|
658 |
{/if}
|
659 |
|
660 |
{#if message.code_executions}
|
|
|
64 |
};
|
65 |
done: boolean;
|
66 |
error?: boolean | { content: string };
|
67 |
+
sources?: string[];
|
68 |
code_executions?: {
|
69 |
uuid: string;
|
70 |
name: string;
|
|
|
621 |
<ContentRenderer
|
622 |
id={message.id}
|
623 |
content={message.content}
|
624 |
+
sources={message.sources}
|
625 |
floatingButtons={message?.done}
|
626 |
save={!readOnly}
|
627 |
{model}
|
628 |
+
onSourceClick={(e) => {
|
629 |
+
console.log(e);
|
630 |
+
const sourceButton = document.getElementById(`source-${e}`);
|
631 |
+
|
632 |
+
if (sourceButton) {
|
633 |
+
sourceButton.click();
|
634 |
+
}
|
635 |
+
}}
|
636 |
on:update={(e) => {
|
637 |
const { raw, oldContent, newContent } = e.detail;
|
638 |
|
|
|
662 |
<Error content={message?.error?.content ?? message.content} />
|
663 |
{/if}
|
664 |
|
665 |
+
{#if (message?.sources || message?.citations) && (model?.info?.meta?.capabilities?.citations ?? true)}
|
666 |
+
<Citations sources={message?.sources ?? message?.citations} />
|
667 |
{/if}
|
668 |
|
669 |
{#if message.code_executions}
|
src/lib/components/chat/Messages/UserMessage.svelte
CHANGED
@@ -5,11 +5,7 @@
|
|
5 |
|
6 |
import { models, settings } from '$lib/stores';
|
7 |
import { user as _user } from '$lib/stores';
|
8 |
-
import {
|
9 |
-
copyToClipboard as _copyToClipboard,
|
10 |
-
processResponseContent,
|
11 |
-
replaceTokens
|
12 |
-
} from '$lib/utils';
|
13 |
|
14 |
import Name from './Name.svelte';
|
15 |
import ProfileImage from './ProfileImage.svelte';
|
|
|
5 |
|
6 |
import { models, settings } from '$lib/stores';
|
7 |
import { user as _user } from '$lib/stores';
|
8 |
+
import { copyToClipboard as _copyToClipboard } from '$lib/utils';
|
|
|
|
|
|
|
|
|
9 |
|
10 |
import Name from './Name.svelte';
|
11 |
import ProfileImage from './ProfileImage.svelte';
|
src/lib/components/common/RichTextInput.svelte
CHANGED
@@ -1,241 +1,46 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import {
|
|
|
|
|
|
|
|
|
3 |
import { createEventDispatcher } from 'svelte';
|
4 |
const eventDispatch = createEventDispatcher();
|
5 |
|
6 |
import { EditorState, Plugin, TextSelection } from 'prosemirror-state';
|
7 |
-
import { EditorView, Decoration, DecorationSet } from 'prosemirror-view';
|
8 |
-
import { undo, redo, history } from 'prosemirror-history';
|
9 |
-
import {
|
10 |
-
schema,
|
11 |
-
defaultMarkdownParser,
|
12 |
-
MarkdownParser,
|
13 |
-
defaultMarkdownSerializer
|
14 |
-
} from 'prosemirror-markdown';
|
15 |
-
|
16 |
-
import {
|
17 |
-
inputRules,
|
18 |
-
wrappingInputRule,
|
19 |
-
textblockTypeInputRule,
|
20 |
-
InputRule
|
21 |
-
} from 'prosemirror-inputrules'; // Import input rules
|
22 |
-
import { splitListItem, liftListItem, sinkListItem } from 'prosemirror-schema-list'; // Import from prosemirror-schema-list
|
23 |
-
import { keymap } from 'prosemirror-keymap';
|
24 |
-
import { baseKeymap, chainCommands } from 'prosemirror-commands';
|
25 |
-
import { DOMParser, DOMSerializer, Schema, Fragment } from 'prosemirror-model';
|
26 |
-
import { PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants';
|
27 |
-
|
28 |
-
export let className = 'input-prose';
|
29 |
-
export let shiftEnter = false;
|
30 |
-
export let largeTextAsFile = false;
|
31 |
-
|
32 |
-
export let id = '';
|
33 |
-
export let value = '';
|
34 |
-
export let placeholder = 'Type here...';
|
35 |
-
export let trim = false;
|
36 |
-
|
37 |
-
let element: HTMLElement; // Element where ProseMirror will attach
|
38 |
-
let state;
|
39 |
-
let view;
|
40 |
-
|
41 |
-
// Plugin to add placeholder when the content is empty
|
42 |
-
function placeholderPlugin(placeholder: string) {
|
43 |
-
return new Plugin({
|
44 |
-
props: {
|
45 |
-
decorations(state) {
|
46 |
-
const doc = state.doc;
|
47 |
-
if (
|
48 |
-
doc.childCount === 1 &&
|
49 |
-
doc.firstChild.isTextblock &&
|
50 |
-
doc.firstChild?.textContent === ''
|
51 |
-
) {
|
52 |
-
// If there's nothing in the editor, show the placeholder decoration
|
53 |
-
const decoration = Decoration.node(0, doc.content.size, {
|
54 |
-
'data-placeholder': placeholder,
|
55 |
-
class: 'placeholder'
|
56 |
-
});
|
57 |
-
return DecorationSet.create(doc, [decoration]);
|
58 |
-
}
|
59 |
-
return DecorationSet.empty;
|
60 |
-
}
|
61 |
-
}
|
62 |
-
});
|
63 |
-
}
|
64 |
-
|
65 |
-
function unescapeMarkdown(text: string): string {
|
66 |
-
return text
|
67 |
-
.replace(/\\([\\`*{}[\]()#+\-.!_>])/g, '$1') // unescape backslashed characters
|
68 |
-
.replace(/&/g, '&')
|
69 |
-
.replace(/</g, '<')
|
70 |
-
.replace(/>/g, '>')
|
71 |
-
.replace(/"/g, '"')
|
72 |
-
.replace(/'/g, "'");
|
73 |
-
}
|
74 |
-
|
75 |
-
// Custom parsing rule that creates proper paragraphs for newlines and empty lines
|
76 |
-
function markdownToProseMirrorDoc(markdown: string) {
|
77 |
-
// Split the markdown into lines
|
78 |
-
const lines = markdown.split('\n\n');
|
79 |
-
|
80 |
-
// Create an array to hold our paragraph nodes
|
81 |
-
const paragraphs = [];
|
82 |
-
|
83 |
-
// Process each line
|
84 |
-
lines.forEach((line) => {
|
85 |
-
if (line.trim() === '') {
|
86 |
-
// For empty lines, create an empty paragraph
|
87 |
-
paragraphs.push(schema.nodes.paragraph.create());
|
88 |
-
} else {
|
89 |
-
// For non-empty lines, parse as usual
|
90 |
-
const doc = defaultMarkdownParser.parse(line);
|
91 |
-
// Extract the content of the parsed document
|
92 |
-
doc.content.forEach((node) => {
|
93 |
-
paragraphs.push(node);
|
94 |
-
});
|
95 |
-
}
|
96 |
-
});
|
97 |
-
|
98 |
-
// Create a new document with these paragraphs
|
99 |
-
return schema.node('doc', null, paragraphs);
|
100 |
-
}
|
101 |
-
|
102 |
-
// Create a custom serializer for paragraphs
|
103 |
-
// Custom paragraph serializer to preserve newlines for empty paragraphs (empty block).
|
104 |
-
function serializeParagraph(state, node: Node) {
|
105 |
-
const content = node.textContent.trim();
|
106 |
-
|
107 |
-
// If the paragraph is empty, just add an empty line.
|
108 |
-
if (content === '') {
|
109 |
-
state.write('\n\n');
|
110 |
-
} else {
|
111 |
-
state.renderInline(node);
|
112 |
-
state.closeBlock(node);
|
113 |
-
}
|
114 |
-
}
|
115 |
-
|
116 |
-
const customMarkdownSerializer = new defaultMarkdownSerializer.constructor(
|
117 |
-
{
|
118 |
-
...defaultMarkdownSerializer.nodes,
|
119 |
-
|
120 |
-
paragraph: (state, node) => {
|
121 |
-
serializeParagraph(state, node); // Use custom paragraph serialization
|
122 |
-
}
|
123 |
-
|
124 |
-
// Customize other block formats if needed
|
125 |
-
},
|
126 |
-
|
127 |
-
// Copy marks directly from the original serializer (or customize them if necessary)
|
128 |
-
defaultMarkdownSerializer.marks
|
129 |
-
);
|
130 |
-
|
131 |
-
// Utility function to convert ProseMirror content back to markdown text
|
132 |
-
function serializeEditorContent(doc) {
|
133 |
-
const markdown = customMarkdownSerializer.serialize(doc);
|
134 |
-
if (trim) {
|
135 |
-
return unescapeMarkdown(markdown).trim();
|
136 |
-
} else {
|
137 |
-
return unescapeMarkdown(markdown);
|
138 |
-
}
|
139 |
-
}
|
140 |
-
|
141 |
-
// ---- Input Rules ----
|
142 |
-
// Input rule for heading (e.g., # Headings)
|
143 |
-
function headingRule(schema) {
|
144 |
-
return textblockTypeInputRule(/^(#{1,6})\s$/, schema.nodes.heading, (match) => ({
|
145 |
-
level: match[1].length
|
146 |
-
}));
|
147 |
-
}
|
148 |
-
|
149 |
-
// Input rule for bullet list (e.g., `- item`)
|
150 |
-
function bulletListRule(schema) {
|
151 |
-
return wrappingInputRule(/^\s*([-+*])\s$/, schema.nodes.bullet_list);
|
152 |
-
}
|
153 |
-
|
154 |
-
// Input rule for ordered list (e.g., `1. item`)
|
155 |
-
function orderedListRule(schema) {
|
156 |
-
return wrappingInputRule(/^(\d+)\.\s$/, schema.nodes.ordered_list, (match) => ({
|
157 |
-
order: +match[1]
|
158 |
-
}));
|
159 |
-
}
|
160 |
-
|
161 |
-
// Custom input rules for Bold/Italic (using * or _)
|
162 |
-
function markInputRule(regexp: RegExp, markType: any) {
|
163 |
-
return new InputRule(regexp, (state, match, start, end) => {
|
164 |
-
const { tr } = state;
|
165 |
-
if (match) {
|
166 |
-
tr.replaceWith(start, end, schema.text(match[1], [markType.create()]));
|
167 |
-
}
|
168 |
-
return tr;
|
169 |
-
});
|
170 |
-
}
|
171 |
-
|
172 |
-
function boldRule(schema) {
|
173 |
-
return markInputRule(/(?<=^|\s)\*([^*]+)\*(?=\s|$)/, schema.marks.strong);
|
174 |
-
}
|
175 |
|
176 |
-
|
177 |
-
// Using lookbehind and lookahead to prevent the space from being consumed
|
178 |
-
return markInputRule(/(?<=^|\s)_([^*_]+)_(?=\s|$)/, schema.marks.em);
|
179 |
-
}
|
180 |
-
|
181 |
-
// Initialize Editor State and View
|
182 |
-
function afterSpacePress(state, dispatch) {
|
183 |
-
// Get the position right after the space was naturally inserted by the browser.
|
184 |
-
let { from, to, empty } = state.selection;
|
185 |
-
|
186 |
-
if (dispatch && empty) {
|
187 |
-
let tr = state.tr;
|
188 |
|
189 |
-
|
190 |
-
|
|
|
|
|
|
|
191 |
|
192 |
-
|
193 |
-
const hasItalic = storedMarks.some((mark) => mark.type === state.schema.marks.em);
|
194 |
|
195 |
-
|
196 |
-
if (hasBold) {
|
197 |
-
tr = tr.removeMark(from - 1, from, state.schema.marks.strong);
|
198 |
-
}
|
199 |
-
if (hasItalic) {
|
200 |
-
tr = tr.removeMark(from - 1, from, state.schema.marks.em);
|
201 |
-
}
|
202 |
-
|
203 |
-
// Dispatch the resulting transaction to update the editor state
|
204 |
-
dispatch(tr);
|
205 |
-
}
|
206 |
|
207 |
-
|
208 |
-
|
209 |
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
if (dispatch) dispatch(state.tr.removeMark(from, to, markType));
|
215 |
-
return true;
|
216 |
-
} else {
|
217 |
-
if (dispatch) dispatch(state.tr.addMark(from, to, markType.create()));
|
218 |
-
return true;
|
219 |
-
}
|
220 |
-
};
|
221 |
-
}
|
222 |
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
$from.parent.type === schema.nodes.paragraph && $from.node(-1).type === schema.nodes.list_item
|
227 |
-
);
|
228 |
-
}
|
229 |
|
230 |
-
|
231 |
-
|
232 |
-
return isInList(state) && $from.parent.content.size === 0 && $from.node(-1).childCount === 1;
|
233 |
-
}
|
234 |
|
235 |
-
|
236 |
-
|
237 |
-
}
|
238 |
|
|
|
239 |
function findNextTemplate(doc, from = 0) {
|
240 |
const patterns = [
|
241 |
{ start: '[', end: ']' },
|
@@ -270,6 +75,7 @@
|
|
270 |
return result;
|
271 |
}
|
272 |
|
|
|
273 |
function selectNextTemplate(state, dispatch) {
|
274 |
const { doc, selection } = state;
|
275 |
const from = selection.to;
|
@@ -290,220 +96,203 @@
|
|
290 |
return false;
|
291 |
}
|
292 |
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
plugins: [
|
306 |
-
history(),
|
307 |
-
placeholderPlugin(placeholder),
|
308 |
-
inputRules({
|
309 |
-
rules: [
|
310 |
-
headingRule(schema), // Handle markdown-style headings (# H1, ## H2, etc.)
|
311 |
-
bulletListRule(schema), // Handle `-` or `*` input to start bullet list
|
312 |
-
orderedListRule(schema), // Handle `1.` input to start ordered list
|
313 |
-
boldRule(schema), // Bold input rule
|
314 |
-
italicRule(schema) // Italic input rule
|
315 |
-
]
|
316 |
}),
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
},
|
339 |
-
baseKeymap.Enter
|
340 |
-
)(state, dispatch, view);
|
341 |
},
|
342 |
-
|
343 |
-
|
344 |
-
if (shiftEnter) {
|
345 |
-
return chainCommands(
|
346 |
-
(state, dispatch, view) => {
|
347 |
-
if (isEmptyListItem(state)) {
|
348 |
-
return exitList(state, dispatch);
|
349 |
-
}
|
350 |
-
return false;
|
351 |
-
},
|
352 |
-
(state, dispatch, view) => {
|
353 |
-
if (isInList(state)) {
|
354 |
-
return splitListItem(schema.nodes.list_item)(state, dispatch);
|
355 |
-
}
|
356 |
-
return false;
|
357 |
-
},
|
358 |
-
baseKeymap.Enter
|
359 |
-
)(state, dispatch, view);
|
360 |
-
} else {
|
361 |
-
return baseKeymap.Enter(state, dispatch, view);
|
362 |
-
}
|
363 |
return false;
|
364 |
},
|
365 |
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
return true; // Prevent Tab from moving the focus
|
375 |
-
}),
|
376 |
-
'Shift-Tab': (state, dispatch, view) => {
|
377 |
-
const { $from } = state.selection;
|
378 |
-
if (isInList(state)) {
|
379 |
-
return liftListItem(schema.nodes.list_item)(state, dispatch);
|
380 |
}
|
381 |
-
return true; // Prevent Shift-Tab from moving the focus
|
382 |
-
},
|
383 |
-
'Mod-b': toggleMark(schema.marks.strong),
|
384 |
-
'Mod-i': toggleMark(schema.marks.em)
|
385 |
-
})
|
386 |
-
]
|
387 |
-
});
|
388 |
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
395 |
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
paste: (view, event) => {
|
413 |
-
if (event.clipboardData) {
|
414 |
-
// Extract plain text from clipboard and paste it without formatting
|
415 |
-
const plainText = event.clipboardData.getData('text/plain');
|
416 |
-
if (plainText) {
|
417 |
-
if (largeTextAsFile) {
|
418 |
-
if (plainText.length > PASTED_TEXT_CHARACTER_LIMIT) {
|
419 |
-
// Dispatch paste event to parent component
|
420 |
-
eventDispatch('paste', { event });
|
421 |
event.preventDefault();
|
422 |
return true;
|
423 |
}
|
424 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
425 |
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
// Replace the current selection with the plain text content
|
430 |
-
const tr = view.state.tr.replaceSelectionWith(
|
431 |
-
view.state.schema.text(modifiedText),
|
432 |
-
false
|
433 |
);
|
434 |
-
view.dispatch(tr.scrollIntoView());
|
435 |
-
event.preventDefault(); // Prevent the default paste behavior
|
436 |
-
return true;
|
437 |
-
}
|
438 |
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
// If there's an image, dispatch the event to the parent
|
450 |
-
eventDispatch('paste', { event });
|
451 |
-
event.preventDefault();
|
452 |
-
return true;
|
453 |
-
}
|
454 |
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
|
|
460 |
}
|
461 |
-
}
|
462 |
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
-
// Handle space input after browser has completed it
|
467 |
-
keyup: (view, event) => {
|
468 |
-
if (event.key === ' ' && event.code === 'Space') {
|
469 |
-
afterSpacePress(view.state, view.dispatch);
|
470 |
}
|
471 |
-
return false;
|
472 |
}
|
473 |
-
}
|
474 |
-
attributes: { id }
|
475 |
-
});
|
476 |
-
});
|
477 |
-
|
478 |
-
// Reinitialize the editor if the value is externally changed (i.e. when `value` is updated)
|
479 |
-
$: if (view && value !== serializeEditorContent(view.state.doc)) {
|
480 |
-
const newDoc = markdownToProseMirrorDoc(value || '');
|
481 |
-
|
482 |
-
const newState = EditorState.create({
|
483 |
-
doc: newDoc,
|
484 |
-
schema,
|
485 |
-
plugins: view.state.plugins,
|
486 |
-
selection: TextSelection.atEnd(newDoc) // This sets the cursor at the end
|
487 |
});
|
488 |
-
view.updateState(newState);
|
489 |
|
490 |
-
|
491 |
-
|
492 |
-
setTimeout(() => {
|
493 |
-
const templateFound = selectNextTemplate(view.state, view.dispatch);
|
494 |
-
if (!templateFound) {
|
495 |
-
// If no template found, set cursor at the end
|
496 |
-
const endPos = view.state.doc.content.size;
|
497 |
-
view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, endPos)));
|
498 |
-
}
|
499 |
-
}, 0);
|
500 |
-
}
|
501 |
-
}
|
502 |
|
503 |
-
// Destroy ProseMirror instance on unmount
|
504 |
onDestroy(() => {
|
505 |
-
|
|
|
|
|
506 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
507 |
</script>
|
508 |
|
509 |
-
<div bind:this={element} class="relative w-full min-w-full h-full min-h-fit {className}"
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { marked } from 'marked';
|
3 |
+
import TurndownService from 'turndown';
|
4 |
+
const turndownService = new TurndownService();
|
5 |
+
|
6 |
+
import { onMount, onDestroy } from 'svelte';
|
7 |
import { createEventDispatcher } from 'svelte';
|
8 |
const eventDispatch = createEventDispatcher();
|
9 |
|
10 |
import { EditorState, Plugin, TextSelection } from 'prosemirror-state';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
+
import { Editor } from '@tiptap/core';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
+
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight';
|
15 |
+
import Placeholder from '@tiptap/extension-placeholder';
|
16 |
+
import Highlight from '@tiptap/extension-highlight';
|
17 |
+
import Typography from '@tiptap/extension-typography';
|
18 |
+
import StarterKit from '@tiptap/starter-kit';
|
19 |
|
20 |
+
import { all, createLowlight } from 'lowlight';
|
|
|
21 |
|
22 |
+
import { PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
+
// create a lowlight instance with all languages loaded
|
25 |
+
const lowlight = createLowlight(all);
|
26 |
|
27 |
+
export let className = 'input-prose';
|
28 |
+
export let placeholder = 'Type here...';
|
29 |
+
export let value = '';
|
30 |
+
export let id = '';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
+
export let messageInput = false;
|
33 |
+
export let shiftEnter = false;
|
34 |
+
export let largeTextAsFile = false;
|
|
|
|
|
|
|
35 |
|
36 |
+
let element;
|
37 |
+
let editor;
|
|
|
|
|
38 |
|
39 |
+
const options = {
|
40 |
+
throwOnError: false
|
41 |
+
};
|
42 |
|
43 |
+
// Function to find the next template in the document
|
44 |
function findNextTemplate(doc, from = 0) {
|
45 |
const patterns = [
|
46 |
{ start: '[', end: ']' },
|
|
|
75 |
return result;
|
76 |
}
|
77 |
|
78 |
+
// Function to select the next template in the document
|
79 |
function selectNextTemplate(state, dispatch) {
|
80 |
const { doc, selection } = state;
|
81 |
const from = selection.to;
|
|
|
96 |
return false;
|
97 |
}
|
98 |
|
99 |
+
export const setContent = (content) => {
|
100 |
+
editor.commands.setContent(content);
|
101 |
+
};
|
102 |
+
|
103 |
+
const selectTemplate = () => {
|
104 |
+
if (value !== '') {
|
105 |
+
// After updating the state, try to find and select the next template
|
106 |
+
setTimeout(() => {
|
107 |
+
const templateFound = selectNextTemplate(editor.view.state, editor.view.dispatch);
|
108 |
+
if (!templateFound) {
|
109 |
+
// If no template found, set cursor at the end
|
110 |
+
const endPos = editor.view.state.doc.content.size;
|
111 |
+
editor.view.dispatch(
|
112 |
+
editor.view.state.tr.setSelection(TextSelection.create(editor.view.state.doc, endPos))
|
113 |
+
);
|
114 |
+
}
|
115 |
+
}, 0);
|
116 |
+
}
|
117 |
+
};
|
118 |
+
|
119 |
+
onMount(async () => {
|
120 |
+
async function tryParse(value, attempts = 3, interval = 100) {
|
121 |
+
try {
|
122 |
+
// Try parsing the value
|
123 |
+
return marked.parse(value);
|
124 |
+
} catch (error) {
|
125 |
+
// If no attempts remain, fallback to plain text
|
126 |
+
if (attempts <= 1) {
|
127 |
+
return value;
|
128 |
+
}
|
129 |
+
// Wait for the interval, then retry
|
130 |
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
131 |
+
return tryParse(value, attempts - 1, interval); // Recursive call
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
// Usage example
|
136 |
+
let content = await tryParse(value);
|
137 |
|
138 |
+
editor = new Editor({
|
139 |
+
element: element,
|
140 |
+
extensions: [
|
141 |
+
StarterKit,
|
142 |
+
CodeBlockLowlight.configure({
|
143 |
+
lowlight
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
}),
|
145 |
+
Highlight,
|
146 |
+
Typography,
|
147 |
+
Placeholder.configure({ placeholder })
|
148 |
+
],
|
149 |
+
content: content,
|
150 |
+
autofocus: true,
|
151 |
+
onTransaction: () => {
|
152 |
+
// force re-render so `editor.isActive` works as expected
|
153 |
+
editor = editor;
|
154 |
+
|
155 |
+
const newValue = turndownService.turndown(editor.getHTML());
|
156 |
+
if (value !== newValue) {
|
157 |
+
value = newValue; // Trigger parent updates
|
158 |
+
}
|
159 |
+
},
|
160 |
+
editorProps: {
|
161 |
+
attributes: { id },
|
162 |
+
handleDOMEvents: {
|
163 |
+
focus: (view, event) => {
|
164 |
+
eventDispatch('focus', { event });
|
165 |
+
return false;
|
|
|
|
|
|
|
166 |
},
|
167 |
+
keypress: (view, event) => {
|
168 |
+
eventDispatch('keypress', { event });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
return false;
|
170 |
},
|
171 |
|
172 |
+
keydown: (view, event) => {
|
173 |
+
// Handle Tab Key
|
174 |
+
if (event.key === 'Tab') {
|
175 |
+
const handled = selectNextTemplate(view.state, view.dispatch);
|
176 |
+
if (handled) {
|
177 |
+
event.preventDefault();
|
178 |
+
return true;
|
179 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
181 |
|
182 |
+
if (messageInput) {
|
183 |
+
if (event.key === 'Enter') {
|
184 |
+
// Check if the current selection is inside a structured block (like codeBlock or list)
|
185 |
+
const { state } = view;
|
186 |
+
const { $head } = state.selection;
|
187 |
+
|
188 |
+
// Recursive function to check ancestors for specific node types
|
189 |
+
function isInside(nodeTypes: string[]): boolean {
|
190 |
+
let currentNode = $head;
|
191 |
+
while (currentNode) {
|
192 |
+
if (nodeTypes.includes(currentNode.parent.type.name)) {
|
193 |
+
return true;
|
194 |
+
}
|
195 |
+
if (!currentNode.depth) break; // Stop if we reach the top
|
196 |
+
currentNode = state.doc.resolve(currentNode.before()); // Move to the parent node
|
197 |
+
}
|
198 |
+
return false;
|
199 |
+
}
|
200 |
+
|
201 |
+
const isInCodeBlock = isInside(['codeBlock']);
|
202 |
+
const isInList = isInside(['listItem', 'bulletList', 'orderedList']);
|
203 |
+
const isInHeading = isInside(['heading']);
|
204 |
|
205 |
+
if (isInCodeBlock || isInList || isInHeading) {
|
206 |
+
// Let ProseMirror handle the normal Enter behavior
|
207 |
+
return false;
|
208 |
+
}
|
209 |
+
}
|
210 |
+
|
211 |
+
// Handle shift + Enter for a line break
|
212 |
+
if (shiftEnter) {
|
213 |
+
if (event.key === 'Enter' && event.shiftKey) {
|
214 |
+
editor.commands.setHardBreak(); // Insert a hard break
|
215 |
+
view.dispatch(view.state.tr.scrollIntoView()); // Move viewport to the cursor
|
216 |
+
event.preventDefault();
|
217 |
+
return true;
|
218 |
+
}
|
219 |
+
if (event.key === 'Enter') {
|
220 |
+
eventDispatch('enter', { event });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
event.preventDefault();
|
222 |
return true;
|
223 |
}
|
224 |
}
|
225 |
+
if (event.key === 'Enter') {
|
226 |
+
eventDispatch('enter', { event });
|
227 |
+
event.preventDefault();
|
228 |
+
return true;
|
229 |
+
}
|
230 |
+
}
|
231 |
+
eventDispatch('keydown', { event });
|
232 |
+
return false;
|
233 |
+
},
|
234 |
+
paste: (view, event) => {
|
235 |
+
if (event.clipboardData) {
|
236 |
+
// Extract plain text from clipboard and paste it without formatting
|
237 |
+
const plainText = event.clipboardData.getData('text/plain');
|
238 |
+
if (plainText) {
|
239 |
+
if (largeTextAsFile) {
|
240 |
+
if (plainText.length > PASTED_TEXT_CHARACTER_LIMIT) {
|
241 |
+
// Dispatch paste event to parent component
|
242 |
+
eventDispatch('paste', { event });
|
243 |
+
event.preventDefault();
|
244 |
+
return true;
|
245 |
+
}
|
246 |
+
}
|
247 |
+
return false;
|
248 |
+
}
|
249 |
|
250 |
+
// Check if the pasted content contains image files
|
251 |
+
const hasImageFile = Array.from(event.clipboardData.files).some((file) =>
|
252 |
+
file.type.startsWith('image/')
|
|
|
|
|
|
|
|
|
253 |
);
|
|
|
|
|
|
|
|
|
254 |
|
255 |
+
// Check for image in dataTransfer items (for cases where files are not available)
|
256 |
+
const hasImageItem = Array.from(event.clipboardData.items).some((item) =>
|
257 |
+
item.type.startsWith('image/')
|
258 |
+
);
|
259 |
+
if (hasImageFile) {
|
260 |
+
// If there's an image, dispatch the event to the parent
|
261 |
+
eventDispatch('paste', { event });
|
262 |
+
event.preventDefault();
|
263 |
+
return true;
|
264 |
+
}
|
|
|
|
|
|
|
|
|
|
|
265 |
|
266 |
+
if (hasImageItem) {
|
267 |
+
// If there's an image item, dispatch the event to the parent
|
268 |
+
eventDispatch('paste', { event });
|
269 |
+
event.preventDefault();
|
270 |
+
return true;
|
271 |
+
}
|
272 |
}
|
|
|
273 |
|
274 |
+
// For all other cases (text, formatted text, etc.), let ProseMirror handle it
|
275 |
+
view.dispatch(view.state.tr.scrollIntoView()); // Move viewport to the cursor after pasting
|
276 |
+
return false;
|
|
|
|
|
|
|
|
|
277 |
}
|
|
|
278 |
}
|
279 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
});
|
|
|
281 |
|
282 |
+
selectTemplate();
|
283 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
284 |
|
|
|
285 |
onDestroy(() => {
|
286 |
+
if (editor) {
|
287 |
+
editor.destroy();
|
288 |
+
}
|
289 |
});
|
290 |
+
|
291 |
+
// Update the editor content if the external `value` changes
|
292 |
+
$: if (editor && value !== turndownService.turndown(editor.getHTML())) {
|
293 |
+
editor.commands.setContent(marked.parse(value)); // Update editor content
|
294 |
+
selectTemplate();
|
295 |
+
}
|
296 |
</script>
|
297 |
|
298 |
+
<div bind:this={element} class="relative w-full min-w-full h-full min-h-fit {className}" />
|
src/lib/components/workspace/Knowledge/KnowledgeBase.svelte
CHANGED
@@ -68,7 +68,7 @@
|
|
68 |
let inputFiles = null;
|
69 |
|
70 |
let filteredItems = [];
|
71 |
-
$: if (knowledge) {
|
72 |
fuse = new Fuse(knowledge.files, {
|
73 |
keys: ['meta.name', 'meta.description']
|
74 |
});
|
|
|
68 |
let inputFiles = null;
|
69 |
|
70 |
let filteredItems = [];
|
71 |
+
$: if (knowledge && knowledge.files) {
|
72 |
fuse = new Fuse(knowledge.files, {
|
73 |
keys: ['meta.name', 'meta.description']
|
74 |
});
|
src/lib/i18n/locales/ar-BH/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "أدخل كود اللغة",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "(e.g. {{modelTag}}) أدخل الموديل تاق",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "(e.g. 50) أدخل عدد الخطوات",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "محتوى الملف النموذجي",
|
570 |
"Models": "الموديلات",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "المزيد",
|
574 |
"Name": "الأسم",
|
|
|
329 |
"Enter language codes": "أدخل كود اللغة",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "(e.g. {{modelTag}}) أدخل الموديل تاق",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "(e.g. 50) أدخل عدد الخطوات",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "محتوى الملف النموذجي",
|
571 |
"Models": "الموديلات",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "المزيد",
|
576 |
"Name": "الأسم",
|
src/lib/i18n/locales/bg-BG/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "Въведете кодове на езика",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Въведете таг на модел (напр. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Въведете брой стъпки (напр. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Съдържание на модфайл",
|
570 |
"Models": "Модели",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "Повече",
|
574 |
"Name": "Име",
|
|
|
329 |
"Enter language codes": "Въведете кодове на езика",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Въведете таг на модел (напр. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Въведете брой стъпки (напр. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "Съдържание на модфайл",
|
571 |
"Models": "Модели",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "Повече",
|
576 |
"Name": "Име",
|
src/lib/i18n/locales/bn-BD/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "ল্যাঙ্গুয়েজ কোড লিখুন",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "মডেল ট্যাগ লিখুন (e.g. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "ধাপের সংখ্যা দিন (যেমন: 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "মডেলফাইল কনটেন্ট",
|
570 |
"Models": "মডেলসমূহ",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "আরো",
|
574 |
"Name": "নাম",
|
|
|
329 |
"Enter language codes": "ল্যাঙ্গুয়েজ কোড লিখুন",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "মডেল ট্যাগ লিখুন (e.g. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "ধাপের সংখ্যা দিন (যেমন: 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "মডেলফাইল কনটেন্ট",
|
571 |
"Models": "মডেলসমূহ",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "আরো",
|
576 |
"Name": "নাম",
|
src/lib/i18n/locales/ca-ES/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "Introdueix els codis de llenguatge",
|
330 |
"Enter Model ID": "Introdueix l'identificador del model",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Introdueix l'etiqueta del model (p. ex. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Introdueix el nombre de passos (p. ex. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "Introdueix el mostrejador (p.ex. Euler a)",
|
334 |
"Enter Scheduler (e.g. Karras)": "Entra el programador (p.ex. Karras)",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Contingut del Modelfile",
|
570 |
"Models": "Models",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "més",
|
573 |
"More": "Més",
|
574 |
"Name": "Nom",
|
|
|
329 |
"Enter language codes": "Introdueix els codis de llenguatge",
|
330 |
"Enter Model ID": "Introdueix l'identificador del model",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Introdueix l'etiqueta del model (p. ex. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Introdueix el nombre de passos (p. ex. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "Introdueix el mostrejador (p.ex. Euler a)",
|
335 |
"Enter Scheduler (e.g. Karras)": "Entra el programador (p.ex. Karras)",
|
|
|
570 |
"Modelfile Content": "Contingut del Modelfile",
|
571 |
"Models": "Models",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "més",
|
575 |
"More": "Més",
|
576 |
"Name": "Nom",
|
src/lib/i18n/locales/ceb-PH/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Pagsulod sa template tag (e.g. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Pagsulod sa gidaghanon sa mga lakang (e.g. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Mga sulod sa template file",
|
570 |
"Models": "Mga modelo",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "",
|
574 |
"Name": "Ngalan",
|
|
|
329 |
"Enter language codes": "",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Pagsulod sa template tag (e.g. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Pagsulod sa gidaghanon sa mga lakang (e.g. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "Mga sulod sa template file",
|
571 |
"Models": "Mga modelo",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "",
|
576 |
"Name": "Ngalan",
|
src/lib/i18n/locales/cs-CZ/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "Zadejte kódy jazyků",
|
330 |
"Enter Model ID": "Zadejte ID modelu",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Zadejte označení modelu (např. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Zadejte počet kroků (např. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "Zadejte vzorkovač (např. Euler a)",
|
334 |
"Enter Scheduler (e.g. Karras)": "Zadejte plánovač (např. Karras)",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Obsah souboru modelfile",
|
570 |
"Models": "Modely",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "více",
|
573 |
"More": "Více",
|
574 |
"Name": "Jméno",
|
|
|
329 |
"Enter language codes": "Zadejte kódy jazyků",
|
330 |
"Enter Model ID": "Zadejte ID modelu",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Zadejte označení modelu (např. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Zadejte počet kroků (např. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "Zadejte vzorkovač (např. Euler a)",
|
335 |
"Enter Scheduler (e.g. Karras)": "Zadejte plánovač (např. Karras)",
|
|
|
570 |
"Modelfile Content": "Obsah souboru modelfile",
|
571 |
"Models": "Modely",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "více",
|
575 |
"More": "Více",
|
576 |
"Name": "Jméno",
|
src/lib/i18n/locales/da-DK/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "Indtast sprogkoder",
|
330 |
"Enter Model ID": "Indtast model-ID",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Indtast modelmærke (f.eks. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Indtast antal trin (f.eks. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "Indtast sampler (f.eks. Euler a)",
|
334 |
"Enter Scheduler (e.g. Karras)": "Indtast scheduler (f.eks. Karras)",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Modelfilindhold",
|
570 |
"Models": "Modeller",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "Mere",
|
574 |
"Name": "Navn",
|
|
|
329 |
"Enter language codes": "Indtast sprogkoder",
|
330 |
"Enter Model ID": "Indtast model-ID",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Indtast modelmærke (f.eks. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Indtast antal trin (f.eks. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "Indtast sampler (f.eks. Euler a)",
|
335 |
"Enter Scheduler (e.g. Karras)": "Indtast scheduler (f.eks. Karras)",
|
|
|
570 |
"Modelfile Content": "Modelfilindhold",
|
571 |
"Models": "Modeller",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "Mere",
|
576 |
"Name": "Navn",
|
src/lib/i18n/locales/de-DE/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "Geben Sie die Sprachcodes ein",
|
330 |
"Enter Model ID": "Geben Sie die Modell-ID ein",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Gebn Sie den Model-Tag ein",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Geben Sie die Anzahl an Schritten ein (z. B. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "Geben Sie den Sampler ein (z. B. Euler a)",
|
334 |
"Enter Scheduler (e.g. Karras)": "Geben Sie den Scheduler ein (z. B. Karras)",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Modelfile-Inhalt",
|
570 |
"Models": "Modelle",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "mehr",
|
573 |
"More": "Mehr",
|
574 |
"Name": "Name",
|
|
|
329 |
"Enter language codes": "Geben Sie die Sprachcodes ein",
|
330 |
"Enter Model ID": "Geben Sie die Modell-ID ein",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Gebn Sie den Model-Tag ein",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Geben Sie die Anzahl an Schritten ein (z. B. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "Geben Sie den Sampler ein (z. B. Euler a)",
|
335 |
"Enter Scheduler (e.g. Karras)": "Geben Sie den Scheduler ein (z. B. Karras)",
|
|
|
570 |
"Modelfile Content": "Modelfile-Inhalt",
|
571 |
"Models": "Modelle",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "mehr",
|
575 |
"More": "Mehr",
|
576 |
"Name": "Name",
|
src/lib/i18n/locales/dg-DG/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Enter model doge tag (e.g. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Enter Number of Steps (e.g. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Modelfile Content",
|
570 |
"Models": "Wowdels",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "",
|
574 |
"Name": "Name",
|
|
|
329 |
"Enter language codes": "",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Enter model doge tag (e.g. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Enter Number of Steps (e.g. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "Modelfile Content",
|
571 |
"Models": "Wowdels",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "",
|
576 |
"Name": "Name",
|
src/lib/i18n/locales/en-GB/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "",
|
570 |
"Models": "",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "",
|
574 |
"Name": "",
|
|
|
329 |
"Enter language codes": "",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "",
|
571 |
"Models": "",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "",
|
576 |
"Name": "",
|
src/lib/i18n/locales/en-US/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "",
|
570 |
"Models": "",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "",
|
574 |
"Name": "",
|
|
|
329 |
"Enter language codes": "",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "",
|
571 |
"Models": "",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "",
|
576 |
"Name": "",
|
src/lib/i18n/locales/es-ES/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "Ingrese códigos de idioma",
|
330 |
"Enter Model ID": "Ingresa el ID del modelo",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Ingrese la etiqueta del modelo (p.ej. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Ingrese el número de pasos (p.ej., 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "Ingrese el sampler (p.ej., Euler a)",
|
334 |
"Enter Scheduler (e.g. Karras)": "Ingrese el planificador (p.ej., Karras)",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Contenido del Modelfile",
|
570 |
"Models": "Modelos",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "Más",
|
574 |
"Name": "Nombre",
|
|
|
329 |
"Enter language codes": "Ingrese códigos de idioma",
|
330 |
"Enter Model ID": "Ingresa el ID del modelo",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Ingrese la etiqueta del modelo (p.ej. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Ingrese el número de pasos (p.ej., 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "Ingrese el sampler (p.ej., Euler a)",
|
335 |
"Enter Scheduler (e.g. Karras)": "Ingrese el planificador (p.ej., Karras)",
|
|
|
570 |
"Modelfile Content": "Contenido del Modelfile",
|
571 |
"Models": "Modelos",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "Más",
|
576 |
"Name": "Nombre",
|
src/lib/i18n/locales/fa-IR/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "کد زبان را وارد کنید",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "تگ مدل را وارد کنید (مثلا {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "تعداد گام ها را وارد کنید (مثال: 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "محتویات فایل مدل",
|
570 |
"Models": "مدل\u200cها",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "بیشتر",
|
574 |
"Name": "نام",
|
|
|
329 |
"Enter language codes": "کد زبان را وارد کنید",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "تگ مدل را وارد کنید (مثلا {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "تعداد گام ها را وارد کنید (مثال: 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "محتویات فایل مدل",
|
571 |
"Models": "مدل\u200cها",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "بیشتر",
|
576 |
"Name": "نام",
|
src/lib/i18n/locales/fi-FI/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "Syötä kielikoodit",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Syötä mallitagi (esim. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Syötä askelien määrä (esim. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Mallitiedoston sisältö",
|
570 |
"Models": "Mallit",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "Lisää",
|
574 |
"Name": "Nimi",
|
|
|
329 |
"Enter language codes": "Syötä kielikoodit",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Syötä mallitagi (esim. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Syötä askelien määrä (esim. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "Mallitiedoston sisältö",
|
571 |
"Models": "Mallit",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "Lisää",
|
576 |
"Name": "Nimi",
|
src/lib/i18n/locales/fr-CA/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "Entrez les codes de langue",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Entrez l'étiquette du modèle (par ex. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Entrez le nombre de pas (par ex. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Contenu du Fichier de Modèle",
|
570 |
"Models": "Modèles",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "Plus de",
|
574 |
"Name": "Nom",
|
|
|
329 |
"Enter language codes": "Entrez les codes de langue",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Entrez l'étiquette du modèle (par ex. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Entrez le nombre de pas (par ex. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "Contenu du Fichier de Modèle",
|
571 |
"Models": "Modèles",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "Plus de",
|
576 |
"Name": "Nom",
|
src/lib/i18n/locales/fr-FR/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "Entrez les codes de langue",
|
330 |
"Enter Model ID": "Entrez l'ID du modèle",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Entrez le tag du modèle (par ex. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "Entrez le nombre d'étapes (par ex. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "Entrez le sampler (par ex. Euler a)",
|
334 |
"Enter Scheduler (e.g. Karras)": "Entrez le planificateur (par ex. Karras)",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "Contenu du Fichier de Modèle",
|
570 |
"Models": "Modèles",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "plus",
|
573 |
"More": "Plus",
|
574 |
"Name": "Nom d'utilisateur",
|
|
|
329 |
"Enter language codes": "Entrez les codes de langue",
|
330 |
"Enter Model ID": "Entrez l'ID du modèle",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Entrez le tag du modèle (par ex. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "Entrez le nombre d'étapes (par ex. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "Entrez le sampler (par ex. Euler a)",
|
335 |
"Enter Scheduler (e.g. Karras)": "Entrez le planificateur (par ex. Karras)",
|
|
|
570 |
"Modelfile Content": "Contenu du Fichier de Modèle",
|
571 |
"Models": "Modèles",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "plus",
|
575 |
"More": "Plus",
|
576 |
"Name": "Nom d'utilisateur",
|
src/lib/i18n/locales/he-IL/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "הזן קודי שפה",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "הזן תג מודל (למשל {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "הזן מספר שלבים (למשל 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "תוכן קובץ מודל",
|
570 |
"Models": "מודלים",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "עוד",
|
574 |
"Name": "שם",
|
|
|
329 |
"Enter language codes": "הזן קודי שפה",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "הזן תג מודל (למשל {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "הזן מספר שלבים (למשל 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "תוכן קובץ מודל",
|
571 |
"Models": "מודלים",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "עוד",
|
576 |
"Name": "שם",
|
src/lib/i18n/locales/hi-IN/translation.json
CHANGED
@@ -329,6 +329,7 @@
|
|
329 |
"Enter language codes": "भाषा कोड दर्ज करें",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Model tag दर्ज करें (उदा. {{modelTag}})",
|
|
|
332 |
"Enter Number of Steps (e.g. 50)": "चरणों की संख्या दर्ज करें (उदा. 50)",
|
333 |
"Enter Sampler (e.g. Euler a)": "",
|
334 |
"Enter Scheduler (e.g. Karras)": "",
|
@@ -569,6 +570,7 @@
|
|
569 |
"Modelfile Content": "मॉडल फ़ाइल सामग्री",
|
570 |
"Models": "सभी मॉडल",
|
571 |
"Models Access": "",
|
|
|
572 |
"more": "",
|
573 |
"More": "और..",
|
574 |
"Name": "नाम",
|
|
|
329 |
"Enter language codes": "भाषा कोड दर्ज करें",
|
330 |
"Enter Model ID": "",
|
331 |
"Enter model tag (e.g. {{modelTag}})": "Model tag दर्ज करें (उदा. {{modelTag}})",
|
332 |
+
"Enter Mojeek Search API Key": "",
|
333 |
"Enter Number of Steps (e.g. 50)": "चरणों की संख्या दर्ज करें (उदा. 50)",
|
334 |
"Enter Sampler (e.g. Euler a)": "",
|
335 |
"Enter Scheduler (e.g. Karras)": "",
|
|
|
570 |
"Modelfile Content": "मॉडल फ़ाइल सामग्री",
|
571 |
"Models": "सभी मॉडल",
|
572 |
"Models Access": "",
|
573 |
+
"Mojeek Search API Key": "",
|
574 |
"more": "",
|
575 |
"More": "और..",
|
576 |
"Name": "नाम",
|