diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1f5dfc6f..2c6f087c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,7 +26,7 @@ jobs: test: name: Run Tests runs-on: ubuntu-latest - container: ubuntu:jammy + container: ubuntu:latest strategy: fail-fast: false matrix: @@ -67,19 +67,19 @@ jobs: env: DEBIAN_FRONTEND: noninteractive run : | - apt install -y postgresql postgresql-client && apt install -y postgresql-server-dev-14 + apt install -y postgresql postgresql-client && apt install -y postgresql-server-dev-16 - name: โฌ‡๏ธ Install pip run: | apt install -y python3-pip - python -m ensurepip --upgrade - python -m pip install --upgrade pip + python3 -m ensurepip --upgrade + python3 -m pip install --upgrade pip - name: โฌ‡๏ธ Install Application env: PIP_EXTRA_INDEX_URL: "https://download.pytorch.org/whl/cpu https://abetlen.github.io/llama-cpp-python/whl/cpu" CUDA_VISIBLE_DEVICES: "" - run: sed -i 's/dynamic = \["version"\]/version = "0.0.0"/' pyproject.toml && pip install --upgrade .[dev] + run: sed -i 's/dynamic = \["version"\]/version = "0.0.0"/' pyproject.toml && pip install --break-system-packages --upgrade .[dev] - name: ๐Ÿงช Test Application env: diff --git a/Dockerfile b/Dockerfile index fab572cc..f7f67e9e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -58,6 +58,6 @@ RUN cd src && python3 khoj/manage.py collectstatic --noinput # Run the Application # There are more arguments required for the application to run, # but those should be passed in through the docker-compose.yml file. -ARG PORT +ARG PORT=42110 EXPOSE ${PORT} ENTRYPOINT ["python3", "src/khoj/main.py"] diff --git a/docker-compose.yml b/docker-compose.yml index da25558e..053dbbbe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,6 @@ services: database: image: ankane/pgvector - restart: always environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres @@ -15,10 +14,8 @@ services: retries: 5 sandbox: image: ghcr.io/khoj-ai/terrarium:latest - restart: unless-stopped search: image: docker.io/searxng/searxng:latest - restart: unless-stopped volumes: - khoj_search:/etc/searxng environment: @@ -29,7 +26,6 @@ services: condition: service_healthy # Use the following line to use the latest version of khoj. Otherwise, it will build from source. Set this to ghcr.io/khoj-ai/khoj-cloud:latest if you want to use the prod image. image: ghcr.io/khoj-ai/khoj:latest - restart: unless-stopped # Uncomment the following line to build from source. This will take a few minutes. Comment the next two lines out if you want to use the official image. # build: # context: . @@ -63,7 +59,7 @@ services: - KHOJ_SEARXNG_URL=http://search:8080 # Uncomment line below to use with Ollama running on your local machine at localhost:11434. # Change URL to use with other OpenAI API compatible providers like VLLM, LMStudio etc. - # - OPENAI_API_BASE=http://host.docker.internal:11434/v1/ + # - OPENAI_BASE_URL=http://host.docker.internal:11434/v1/ # # Uncomment appropriate lines below to use chat models by OpenAI, Anthropic, Google. # Ensure you set your provider specific API keys. diff --git a/documentation/docs/advanced/ollama.mdx b/documentation/docs/advanced/ollama.mdx index 486357e8..1140f33b 100644 --- a/documentation/docs/advanced/ollama.mdx +++ b/documentation/docs/advanced/ollama.mdx @@ -32,7 +32,7 @@ Restart your Khoj server after first run or update to the settings below to ensu ```bash ollama pull llama3.1 ``` - 3. Uncomment `OPENAI_API_BASE` environment variable in your downloaded Khoj [docker-compose.yml](https://github.com/khoj-ai/khoj/blob/master/docker-compose.yml#:~:text=OPENAI_API_BASE) + 3. Uncomment `OPENAI_BASE_URL` environment variable in your downloaded Khoj [docker-compose.yml](https://github.com/khoj-ai/khoj/blob/master/docker-compose.yml#:~:text=OPENAI_BASE_URL) 4. Start Khoj docker for the first time to automatically integrate and load models from the Ollama running on your host machine ```bash # run below command in the directory where you downloaded the Khoj docker-compose.yml @@ -46,9 +46,9 @@ Restart your Khoj server after first run or update to the settings below to ensu ```bash ollama pull llama3.1 ``` - 3. Set `OPENAI_API_BASE` environment variable to `http://localhost:11434/v1/` in your shell before starting Khoj for the first time + 3. Set `OPENAI_BASE_URL` environment variable to `http://localhost:11434/v1/` in your shell before starting Khoj for the first time ```bash - export OPENAI_API_BASE="http://localhost:11434/v1/" + export OPENAI_BASE_URL="http://localhost:11434/v1/" khoj --anonymous-mode ``` diff --git a/documentation/docs/features/search.md b/documentation/docs/features/search.md index 810a886b..70410f67 100644 --- a/documentation/docs/features/search.md +++ b/documentation/docs/features/search.md @@ -15,3 +15,37 @@ Take advantage of super fast search to find relevant notes and documents from yo ### Demo ![](/img/search_agents_markdown.png ':size=400px') + + +### Implementation Overview +A bi-encoder models is used to create meaning vectors (aka vector embeddings) of your documents and search queries. +1. When you sync you documents with Khoj, it uses the bi-encoder model to create and store meaning vectors of (chunks of) your documents +2. When you initiate a natural language search the bi-encoder model converts your query into a meaning vector and finds the most relevant document chunks for that query by comparing their meaning vectors. +3. The slower but higher-quality cross-encoder model is than used to re-rank these documents for your given query. + +### Setup (Self-Hosting) +You are **not required** to configure the search model config when self-hosting. Khoj sets up decent default local search model config for general use. + +You may want to configure this if you need better multi-lingual search, want to experiment with different, newer models or the default models do not work for your use-case. + +You can use bi-encoder models downloaded locally [from Huggingface](https://huggingface.co/models?library=sentence-transformers), served via the [HuggingFace Inference API](https://endpoints.huggingface.co/), OpenAI API, Azure OpenAI API or any OpenAI Compatible API like Ollama, LiteLLM etc. Follow the steps below to configure your search model: + +1. Open the [SearchModelConfig](http://localhost:42110/server/admin/database/searchmodelconfig/) page on your Khoj admin panel. +2. Hit the Plus button to add a new model config or click the id of an existing model config to edit it. +3. Set the `biencoder` field to the name of the bi-encoder model supported [locally](https://huggingface.co/models?library=sentence-transformers) or via the API you configure. +4. Set the `Embeddings inference endpoint api key` to your OpenAI API key and `Embeddings inference endpoint type` to `OpenAI` to use an OpenAI embedding model. +5. Also set the `Embeddings inference endpoint` to your Azure OpenAI or OpenAI compatible API URL to use the model via those APIs. +6. Ensure the search model config you want to use is the **only one** that has `name` field set to `default`[^1]. +7. Save the search model configs and restart your Khoj server to start using your new, updated search config. + +:::info +You will need to re-index all your documents if you want to use a different bi-encoder model. +::: + +:::info +You may need to tune the `Bi encoder confidence threshold` field for each bi-encoder to get appropriate number of documents for chat with your Knowledge base. + +Confidence here is a normalized measure of semantic distance between your query and documents. The confidence threshold limits the documents returned to chat that fall within the distance specified in this field. It can take values between 0.0 (exact overlap) and 1.0 (no meaning overlap). +::: + +[^1]: Khoj uses the first search model config named `default` it finds on startup as the search model config for that session diff --git a/documentation/docs/get-started/setup.mdx b/documentation/docs/get-started/setup.mdx index 17d18aea..7a2cbb16 100644 --- a/documentation/docs/get-started/setup.mdx +++ b/documentation/docs/get-started/setup.mdx @@ -48,7 +48,7 @@ Restart your Khoj server after the first run to ensure all settings are applied 2. Configure the environment variables in the `docker-compose.yml` - Set `KHOJ_ADMIN_PASSWORD`, `KHOJ_DJANGO_SECRET_KEY` (and optionally the `KHOJ_ADMIN_EMAIL`) to something secure. This allows you to customize Khoj later via the admin panel. - Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `GEMINI_API_KEY` to your API key if you want to use OpenAI, Anthropic or Gemini commercial chat models respectively. - - Uncomment `OPENAI_API_BASE` to use [Ollama](/advanced/ollama?type=first-run&server=docker#setup) running on your host machine. Or set it to the URL of your OpenAI compatible API like vLLM or [LMStudio](/advanced/lmstudio). + - Uncomment `OPENAI_BASE_URL` to use [Ollama](/advanced/ollama?type=first-run&server=docker#setup) running on your host machine. Or set it to the URL of your OpenAI compatible API like vLLM or [LMStudio](/advanced/lmstudio). 3. Start Khoj by running the following command in the same directory as your docker-compose.yml file. ```shell cd ~/.khoj @@ -74,7 +74,7 @@ Restart your Khoj server after the first run to ensure all settings are applied 2. Configure the environment variables in the `docker-compose.yml` - Set `KHOJ_ADMIN_PASSWORD`, `KHOJ_DJANGO_SECRET_KEY` (and optionally the `KHOJ_ADMIN_EMAIL`) to something secure. This allows you to customize Khoj later via the admin panel. - Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `GEMINI_API_KEY` to your API key if you want to use OpenAI, Anthropic or Gemini commercial chat models respectively. - - Uncomment `OPENAI_API_BASE` to use [Ollama](/advanced/ollama) running on your host machine. Or set it to the URL of your OpenAI compatible API like vLLM or [LMStudio](/advanced/lmstudio). + - Uncomment `OPENAI_BASE_URL` to use [Ollama](/advanced/ollama) running on your host machine. Or set it to the URL of your OpenAI compatible API like vLLM or [LMStudio](/advanced/lmstudio). 3. Start Khoj by running the following command in the same directory as your docker-compose.yml file. ```shell # Windows users should use their WSL2 terminal to run these commands @@ -96,7 +96,7 @@ Restart your Khoj server after the first run to ensure all settings are applied 2. Configure the environment variables in the `docker-compose.yml` - Set `KHOJ_ADMIN_PASSWORD`, `KHOJ_DJANGO_SECRET_KEY` (and optionally the `KHOJ_ADMIN_EMAIL`) to something secure. This allows you to customize Khoj later via the admin panel. - Set `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `GEMINI_API_KEY` to your API key if you want to use OpenAI, Anthropic or Gemini commercial chat models respectively. - - Uncomment `OPENAI_API_BASE` to use [Ollama](/advanced/ollama) running on your host machine. Or set it to the URL of your OpenAI compatible API like vLLM or [LMStudio](/advanced/lmstudio). + - Uncomment `OPENAI_BASE_URL` to use [Ollama](/advanced/ollama) running on your host machine. Or set it to the URL of your OpenAI compatible API like vLLM or [LMStudio](/advanced/lmstudio). 3. Start Khoj by running the following command in the same directory as your docker-compose.yml file. ```shell cd ~/.khoj diff --git a/manifest.json b/manifest.json index 3e5f8331..6c8ad3bf 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "khoj", "name": "Khoj", - "version": "1.33.2", + "version": "1.34.0", "minAppVersion": "0.15.0", "description": "Your Second Brain", "author": "Khoj Inc.", diff --git a/src/interface/desktop/chatutils.js b/src/interface/desktop/chatutils.js index 48fb72c3..7fb05e1a 100644 --- a/src/interface/desktop/chatutils.js +++ b/src/interface/desktop/chatutils.js @@ -229,7 +229,7 @@ function generateImageMarkdown(message, intentType, inferredQueries=null) { //sa } else if (intentType === "text-to-image2") { imageMarkdown = `![](${message})`; } else if (intentType === "text-to-image-v3") { - imageMarkdown = `![](data:image/webp;base64,${message})`; + imageMarkdown = `![](${message})`; } const inferredQuery = inferredQueries?.[0]; if (inferredQuery) { @@ -423,7 +423,7 @@ function handleImageResponse(imageJson, rawResponse) { } else if (imageJson.intentType === "text-to-image2") { rawResponse += `![generated_image](${imageJson.image})`; } else if (imageJson.intentType === "text-to-image-v3") { - rawResponse = `![](data:image/webp;base64,${imageJson.image})`; + rawResponse = `![](${imageJson.image})`; } else if (imageJson.intentType === "excalidraw") { const redirectMessage = `Hey, I'm not ready to show you diagrams yet here. But you can view it in the web app`; rawResponse += redirectMessage; diff --git a/src/interface/desktop/package.json b/src/interface/desktop/package.json index ef28b055..e7d0a4c2 100644 --- a/src/interface/desktop/package.json +++ b/src/interface/desktop/package.json @@ -1,6 +1,6 @@ { "name": "Khoj", - "version": "1.33.2", + "version": "1.34.0", "description": "Your Second Brain", "author": "Khoj Inc. ", "license": "GPL-3.0-or-later", diff --git a/src/interface/emacs/khoj.el b/src/interface/emacs/khoj.el index 828139b0..d832fc51 100644 --- a/src/interface/emacs/khoj.el +++ b/src/interface/emacs/khoj.el @@ -6,7 +6,7 @@ ;; Saba Imran ;; Description: Your Second Brain ;; Keywords: search, chat, ai, org-mode, outlines, markdown, pdf, image -;; Version: 1.33.2 +;; Version: 1.34.0 ;; Package-Requires: ((emacs "27.1") (transient "0.3.0") (dash "2.19.1")) ;; URL: https://github.com/khoj-ai/khoj/tree/master/src/interface/emacs diff --git a/src/interface/obsidian/manifest.json b/src/interface/obsidian/manifest.json index 3e5f8331..6c8ad3bf 100644 --- a/src/interface/obsidian/manifest.json +++ b/src/interface/obsidian/manifest.json @@ -1,7 +1,7 @@ { "id": "khoj", "name": "Khoj", - "version": "1.33.2", + "version": "1.34.0", "minAppVersion": "0.15.0", "description": "Your Second Brain", "author": "Khoj Inc.", diff --git a/src/interface/obsidian/package.json b/src/interface/obsidian/package.json index 76a82635..2ef8b849 100644 --- a/src/interface/obsidian/package.json +++ b/src/interface/obsidian/package.json @@ -1,6 +1,6 @@ { "name": "Khoj", - "version": "1.33.2", + "version": "1.34.0", "description": "Your Second Brain", "author": "Debanjum Singh Solanky, Saba Imran ", "license": "GPL-3.0-or-later", diff --git a/src/interface/obsidian/src/chat_view.ts b/src/interface/obsidian/src/chat_view.ts index 86d5e1f9..b9a5322d 100644 --- a/src/interface/obsidian/src/chat_view.ts +++ b/src/interface/obsidian/src/chat_view.ts @@ -487,7 +487,8 @@ export class KhojChatView extends KhojPaneView { inferredQueries?: string[], conversationId?: string, images?: string[], - excalidrawDiagram?: string + excalidrawDiagram?: string, + mermaidjsDiagram?: string ) { if (!message) return; @@ -496,8 +497,9 @@ export class KhojChatView extends KhojPaneView { intentType?.includes("text-to-image") || intentType === "excalidraw" || (images && images.length > 0) || + mermaidjsDiagram || excalidrawDiagram) { - let imageMarkdown = this.generateImageMarkdown(message, intentType ?? "", inferredQueries, conversationId, images, excalidrawDiagram); + let imageMarkdown = this.generateImageMarkdown(message, intentType ?? "", inferredQueries, conversationId, images, excalidrawDiagram, mermaidjsDiagram); chatMessageEl = this.renderMessage(chatEl, imageMarkdown, sender, dt); } else { chatMessageEl = this.renderMessage(chatEl, message, sender, dt); @@ -517,28 +519,23 @@ export class KhojChatView extends KhojPaneView { chatMessageBodyEl.appendChild(this.createReferenceSection(references)); } - generateImageMarkdown(message: string, intentType: string, inferredQueries?: string[], conversationId?: string, images?: string[], excalidrawDiagram?: string): string { + generateImageMarkdown(message: string, intentType: string, inferredQueries?: string[], conversationId?: string, images?: string[], excalidrawDiagram?: string, mermaidjsDiagram?: string): string { let imageMarkdown = ""; if (intentType === "text-to-image") { imageMarkdown = `![](data:image/png;base64,${message})`; } else if (intentType === "text-to-image2") { imageMarkdown = `![](${message})`; } else if (intentType === "text-to-image-v3") { - imageMarkdown = `![](data:image/webp;base64,${message})`; + imageMarkdown = `![](${message})`; } else if (intentType === "excalidraw" || excalidrawDiagram) { const domain = this.setting.khojUrl.endsWith("/") ? this.setting.khojUrl : `${this.setting.khojUrl}/`; const redirectMessage = `Hey, I'm not ready to show you diagrams yet here. But you can view it in ${domain}chat?conversationId=${conversationId}`; imageMarkdown = redirectMessage; + } else if (mermaidjsDiagram) { + imageMarkdown = "```mermaid\n" + mermaidjsDiagram + "\n```"; } else if (images && images.length > 0) { - for (let image of images) { - if (image.startsWith("https://")) { - imageMarkdown += `![](${image})\n\n`; - } else { - imageMarkdown += `![](data:image/png;base64,${image})\n\n`; - } - } - - imageMarkdown += `${message}`; + imageMarkdown += images.map(image => `![](${image})`).join('\n\n'); + imageMarkdown += message; } if (images?.length === 0 && inferredQueries) { @@ -908,6 +905,7 @@ export class KhojChatView extends KhojPaneView { chatBodyEl.dataset.conversationId ?? "", chatLog.images, chatLog.excalidrawDiagram, + chatLog.mermaidjsDiagram, ); // push the user messages to the chat history if (chatLog.by === "you") { @@ -1012,7 +1010,7 @@ export class KhojChatView extends KhojPaneView { } handleJsonResponse(jsonData: any): void { - if (jsonData.image || jsonData.detail || jsonData.images || jsonData.excalidrawDiagram) { + if (jsonData.image || jsonData.detail || jsonData.images || jsonData.mermaidjsDiagram) { this.chatMessageState.rawResponse = this.handleImageResponse(jsonData, this.chatMessageState.rawResponse); } else if (jsonData.response) { this.chatMessageState.rawResponse = jsonData.response; @@ -1384,7 +1382,7 @@ export class KhojChatView extends KhojPaneView { } else if (imageJson.intentType === "text-to-image2") { rawResponse += `![generated_image](${imageJson.image})`; } else if (imageJson.intentType === "text-to-image-v3") { - rawResponse = `![](data:image/webp;base64,${imageJson.image})`; + rawResponse = `![generated_image](${imageJson.image})`; } else if (imageJson.intentType === "excalidraw") { const domain = this.setting.khojUrl.endsWith("/") ? this.setting.khojUrl : `${this.setting.khojUrl}/`; const redirectMessage = `Hey, I'm not ready to show you diagrams yet here. But you can view it in ${domain}`; @@ -1396,17 +1394,14 @@ export class KhojChatView extends KhojPaneView { } else if (imageJson.images) { // If response has images field, response is a list of generated images. imageJson.images.forEach((image: any) => { - - if (image.startsWith("http")) { - rawResponse += `![generated_image](${image})\n\n`; - } else { - rawResponse += `![generated_image](data:image/png;base64,${image})\n\n`; - } + rawResponse += `![generated_image](${image})\n\n`; }); } else if (imageJson.excalidrawDiagram) { const domain = this.setting.khojUrl.endsWith("/") ? this.setting.khojUrl : `${this.setting.khojUrl}/`; const redirectMessage = `Hey, I'm not ready to show you diagrams yet here. But you can view it in ${domain}`; rawResponse += redirectMessage; + } else if (imageJson.mermaidjsDiagram) { + rawResponse += imageJson.mermaidjsDiagram; } // If response has detail field, response is an error message. diff --git a/src/interface/obsidian/versions.json b/src/interface/obsidian/versions.json index e7dced26..47ff6efa 100644 --- a/src/interface/obsidian/versions.json +++ b/src/interface/obsidian/versions.json @@ -108,5 +108,6 @@ "1.32.2": "0.15.0", "1.33.0": "0.15.0", "1.33.1": "0.15.0", - "1.33.2": "0.15.0" + "1.33.2": "0.15.0", + "1.34.0": "0.15.0" } diff --git a/src/interface/web/app/chat/page.tsx b/src/interface/web/app/chat/page.tsx index ff7cb796..824a7e4c 100644 --- a/src/interface/web/app/chat/page.tsx +++ b/src/interface/web/app/chat/page.tsx @@ -354,7 +354,15 @@ export default function Chat() { try { await readChatStream(response); } catch (err) { - const apiError = await response.json(); + let apiError; + try { + apiError = await response.json(); + } catch (err) { + // Error reading API error response + apiError = { + streamError: "Error reading API error response stream. Expected JSON response.", + }; + } console.error(apiError); // Retrieve latest message being processed const currentMessage = messages.find((message) => !message.completed); @@ -365,7 +373,9 @@ export default function Chat() { const errorName = (err as Error).name; if (errorMessage.includes("Error in input stream")) currentMessage.rawResponse = `Woops! The connection broke while I was writing my thoughts down. Maybe try again in a bit or dislike this message if the issue persists?`; - else if (response.status === 429) { + else if (apiError.streamError) { + currentMessage.rawResponse = `Umm, not sure what just happened but I lost my train of thought. Could you try again or ask my developers to look into this if the issue persists? They can be contacted at the Khoj Github, Discord or team@khoj.dev.`; + } else if (response.status === 429) { "detail" in apiError ? (currentMessage.rawResponse = `${apiError.detail}`) : (currentMessage.rawResponse = `I'm a bit overwhelmed at the moment. Could you try again in a bit or dislike this message if the issue persists?`); diff --git a/src/interface/web/app/common/chatFunctions.ts b/src/interface/web/app/common/chatFunctions.ts index c64e81ba..be64acf1 100644 --- a/src/interface/web/app/common/chatFunctions.ts +++ b/src/interface/web/app/common/chatFunctions.ts @@ -19,7 +19,7 @@ export interface MessageMetadata { export interface GeneratedAssetsData { images: string[]; - excalidrawDiagram: string; + mermaidjsDiagram: string; files: AttachedFileText[]; } @@ -114,8 +114,8 @@ export function processMessageChunk( currentMessage.generatedImages = generatedAssets.images; } - if (generatedAssets.excalidrawDiagram) { - currentMessage.generatedExcalidrawDiagram = generatedAssets.excalidrawDiagram; + if (generatedAssets.mermaidjsDiagram) { + currentMessage.generatedMermaidjsDiagram = generatedAssets.mermaidjsDiagram; } if (generatedAssets.files) { diff --git a/src/interface/web/app/components/chatHistory/chatHistory.tsx b/src/interface/web/app/components/chatHistory/chatHistory.tsx index 5a750e8b..829211be 100644 --- a/src/interface/web/app/components/chatHistory/chatHistory.tsx +++ b/src/interface/web/app/components/chatHistory/chatHistory.tsx @@ -418,7 +418,7 @@ export default function ChatHistory(props: ChatHistoryProps) { conversationId: props.conversationId, images: message.generatedImages, queryFiles: message.generatedFiles, - excalidrawDiagram: message.generatedExcalidrawDiagram, + mermaidjsDiagram: message.generatedMermaidjsDiagram, turnId: messageTurnId, }} conversationId={props.conversationId} diff --git a/src/interface/web/app/components/chatMessage/chatMessage.tsx b/src/interface/web/app/components/chatMessage/chatMessage.tsx index 89c3038a..c3227f59 100644 --- a/src/interface/web/app/components/chatMessage/chatMessage.tsx +++ b/src/interface/web/app/components/chatMessage/chatMessage.tsx @@ -53,6 +53,7 @@ import { DialogTitle } from "@radix-ui/react-dialog"; import { convertBytesToText } from "@/app/common/utils"; import { ScrollArea } from "@/components/ui/scroll-area"; import { getIconFromFilename } from "@/app/common/iconUtils"; +import Mermaid from "../mermaid/mermaid"; const md = new markdownIt({ html: true, @@ -164,6 +165,7 @@ export interface SingleChatMessage { turnId?: string; queryFiles?: AttachedFileText[]; excalidrawDiagram?: string; + mermaidjsDiagram?: string; } export interface StreamMessage { @@ -182,9 +184,11 @@ export interface StreamMessage { turnId?: string; queryFiles?: AttachedFileText[]; excalidrawDiagram?: string; + mermaidjsDiagram?: string; generatedFiles?: AttachedFileText[]; generatedImages?: string[]; generatedExcalidrawDiagram?: string; + generatedMermaidjsDiagram?: string; } export interface ChatHistoryData { @@ -271,6 +275,7 @@ interface ChatMessageProps { turnId?: string; generatedImage?: string; excalidrawDiagram?: string; + mermaidjsDiagram?: string; generatedFiles?: AttachedFileText[]; } @@ -358,6 +363,7 @@ const ChatMessage = forwardRef((props, ref) => const [isPlaying, setIsPlaying] = useState(false); const [interrupted, setInterrupted] = useState(false); const [excalidrawData, setExcalidrawData] = useState(""); + const [mermaidjsData, setMermaidjsData] = useState(""); const interruptedRef = useRef(false); const messageRef = useRef(null); @@ -401,6 +407,10 @@ const ChatMessage = forwardRef((props, ref) => setExcalidrawData(props.chatMessage.excalidrawDiagram); } + if (props.chatMessage.mermaidjsDiagram) { + setMermaidjsData(props.chatMessage.mermaidjsDiagram); + } + // Replace LaTeX delimiters with placeholders message = message .replace(/\\\(/g, "LEFTPAREN") @@ -718,6 +728,7 @@ const ChatMessage = forwardRef((props, ref) => dangerouslySetInnerHTML={{ __html: markdownRendered }} /> {excalidrawData && } + {mermaidjsData && }
-
- {props.message || "Loading"}{" "} - - - + + + +
+ + + {isMobileWidth ? ( + + + + ) : ( +

Ask Anything

+ )} +
+
+
+
+ {props.message || "Loading"}{" "} + + + +
-
+ ); } diff --git a/src/interface/web/app/components/loginPrompt/loginPrompt.tsx b/src/interface/web/app/components/loginPrompt/loginPrompt.tsx index 5cda444a..633d7b41 100644 --- a/src/interface/web/app/components/loginPrompt/loginPrompt.tsx +++ b/src/interface/web/app/components/loginPrompt/loginPrompt.tsx @@ -2,7 +2,7 @@ import styles from "./loginPrompt.module.css"; import { Button } from "@/components/ui/button"; -import { Dialog, DialogContent } from "@/components/ui/dialog"; +import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import Autoplay from "embla-carousel-autoplay"; import { @@ -27,6 +27,7 @@ import { } from "@/components/ui/carousel"; import { Card, CardContent } from "@/components/ui/card"; import { InputOTP, InputOTPGroup, InputOTPSlot } from "@/components/ui/input-otp"; +import * as VisuallyHidden from "@radix-ui/react-visually-hidden"; export interface LoginPromptProps { onOpenChange: (open: boolean) => void; @@ -181,6 +182,9 @@ export default function LoginPrompt(props: LoginPromptProps) { + + Login Dialog +
{useEmailSignIn ? ( = ALLOWED_OTP_ATTEMPTS) { setOTPError("Too many failed attempts. Please try again tomorrow."); diff --git a/src/interface/web/app/components/mermaid/mermaid.tsx b/src/interface/web/app/components/mermaid/mermaid.tsx new file mode 100644 index 00000000..d73a4447 --- /dev/null +++ b/src/interface/web/app/components/mermaid/mermaid.tsx @@ -0,0 +1,173 @@ +import React, { useEffect, useState, useRef } from "react"; +import mermaid from "mermaid"; +import { Download, Info } from "@phosphor-icons/react"; +import { Button } from "@/components/ui/button"; + +interface MermaidProps { + chart: string; +} + +const Mermaid: React.FC = ({ chart }) => { + const [mermaidError, setMermaidError] = useState(null); + const [mermaidId] = useState(`mermaid-chart-${Math.random().toString(12).substring(7)}`); + const elementRef = useRef(null); + + useEffect(() => { + mermaid.initialize({ + startOnLoad: false, + }); + + mermaid.parseError = (error) => { + console.error("Mermaid errors:", error); + // Extract error message from error object + // Parse error message safely + let errorMessage; + try { + errorMessage = typeof error === "string" ? JSON.parse(error) : error; + } catch (e) { + errorMessage = error?.toString() || "Unknown error"; + } + + console.log("Mermaid error message:", errorMessage); + + if (errorMessage.str !== "element is null") { + setMermaidError( + "Something went wrong while rendering the diagram. Please try again later or downvote the message if the issue persists.", + ); + } else { + setMermaidError(null); + } + }; + + mermaid.contentLoaded(); + }, []); + + const handleExport = async () => { + if (!elementRef.current) return; + + try { + // Get SVG element + const svgElement = elementRef.current.querySelector("svg"); + if (!svgElement) throw new Error("No SVG found"); + + // Get SVG viewBox dimensions + const viewBox = svgElement.getAttribute("viewBox")?.split(" ").map(Number) || [ + 0, 0, 0, 0, + ]; + const [, , viewBoxWidth, viewBoxHeight] = viewBox; + + // Create canvas with viewBox dimensions + const canvas = document.createElement("canvas"); + const scale = 2; // For better resolution + canvas.width = viewBoxWidth * scale; + canvas.height = viewBoxHeight * scale; + const ctx = canvas.getContext("2d"); + if (!ctx) throw new Error("Failed to get canvas context"); + + // Convert SVG to data URL + const svgData = new XMLSerializer().serializeToString(svgElement); + const svgBlob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" }); + const svgUrl = URL.createObjectURL(svgBlob); + + // Create and load image + const img = new Image(); + img.src = svgUrl; + + await new Promise((resolve, reject) => { + img.onload = () => { + // Scale context for better resolution + ctx.scale(scale, scale); + ctx.drawImage(img, 0, 0, viewBoxWidth, viewBoxHeight); + + canvas.toBlob((blob) => { + if (!blob) { + reject(new Error("Failed to create blob")); + return; + } + + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `mermaid-diagram-${Date.now()}.png`; + a.click(); + + // Cleanup + URL.revokeObjectURL(url); + URL.revokeObjectURL(svgUrl); + resolve(true); + }, "image/png"); + }; + + img.onerror = () => reject(new Error("Failed to load SVG")); + }); + } catch (error) { + console.error("Error exporting diagram:", error); + setMermaidError("Failed to export diagram"); + } + }; + + useEffect(() => { + if (elementRef.current) { + elementRef.current.removeAttribute("data-processed"); + + mermaid + .run({ + nodes: [elementRef.current], + }) + .then(() => { + setMermaidError(null); + }) + .catch((error) => { + let errorMessage; + try { + errorMessage = typeof error === "string" ? JSON.parse(error) : error; + } catch (e) { + errorMessage = error?.toString() || "Unknown error"; + } + + console.log("Mermaid error message:", errorMessage); + + if (errorMessage.str !== "element is null") { + setMermaidError( + "Something went wrong while rendering the diagram. Please try again later or downvote the message if the issue persists.", + ); + } else { + setMermaidError(null); + } + }); + } + }, [chart]); + + return ( +
+ {mermaidError ? ( +
+ + Error rendering diagram: {mermaidError} +
+ ) : ( +
+ {chart} +
+ )} + {!mermaidError && ( + + )} +
+ ); +}; + +export default Mermaid; diff --git a/src/interface/web/package.json b/src/interface/web/package.json index 3fa63f26..b7f6bb5d 100644 --- a/src/interface/web/package.json +++ b/src/interface/web/package.json @@ -1,6 +1,6 @@ { "name": "khoj-ai", - "version": "1.33.2", + "version": "1.34.0", "private": true, "scripts": { "dev": "next dev", @@ -53,12 +53,13 @@ "eslint-config-next": "14.2.3", "input-otp": "^1.2.4", "intl-tel-input": "^23.8.1", - "katex": "^0.16.10", + "katex": "^0.16.21", "libphonenumber-js": "^1.11.4", "lucide-react": "^0.468.0", "markdown-it": "^14.1.0", "markdown-it-highlightjs": "^4.1.0", - "next": "14.2.15", + "mermaid": "^11.4.1", + "next": "14.2.21", "nodemon": "^3.1.3", "postcss": "^8.4.38", "react": "^18", diff --git a/src/interface/web/yarn.lock b/src/interface/web/yarn.lock index 200bdab8..05031338 100644 --- a/src/interface/web/yarn.lock +++ b/src/interface/web/yarn.lock @@ -15,11 +15,24 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" +"@antfu/install-pkg@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@antfu/install-pkg/-/install-pkg-0.4.1.tgz#d1d7f3be96ecdb41581629cafe8626d1748c0cf1" + integrity sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw== + dependencies: + package-manager-detector "^0.2.0" + tinyexec "^0.3.0" + "@antfu/ni@^0.21.4": version "0.21.12" resolved "https://registry.yarnpkg.com/@antfu/ni/-/ni-0.21.12.tgz#54d33cf0e6d35cb2ec12ab3d5092e4904540b7c0" integrity sha512-2aDL3WUv8hMJb2L3r/PIQWsTLyq7RQr3v9xD16fiz6O8ys1xEyLhhTOv8gxtZvJiTzjTF5pHoArvRdesGL1DMQ== +"@antfu/utils@^0.7.10": + version "0.7.10" + resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.7.10.tgz#ae829f170158e297a9b6a28f161a8e487d00814d" + integrity sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww== + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" @@ -229,6 +242,43 @@ "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" +"@braintree/sanitize-url@^7.0.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz#15e19737d946559289b915e5dad3b4c28407735e" + integrity sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw== + +"@chevrotain/cst-dts-gen@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz#5e0863cc57dc45e204ccfee6303225d15d9d4783" + integrity sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ== + dependencies: + "@chevrotain/gast" "11.0.3" + "@chevrotain/types" "11.0.3" + lodash-es "4.17.21" + +"@chevrotain/gast@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/gast/-/gast-11.0.3.tgz#e84d8880323fe8cbe792ef69ce3ffd43a936e818" + integrity sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q== + dependencies: + "@chevrotain/types" "11.0.3" + lodash-es "4.17.21" + +"@chevrotain/regexp-to-ast@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz#11429a81c74a8e6a829271ce02fc66166d56dcdb" + integrity sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA== + +"@chevrotain/types@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/types/-/types-11.0.3.tgz#f8a03914f7b937f594f56eb89312b3b8f1c91848" + integrity sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ== + +"@chevrotain/utils@11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@chevrotain/utils/-/utils-11.0.3.tgz#e39999307b102cff3645ec4f5b3665f5297a2224" + integrity sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.1" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" @@ -317,6 +367,25 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@iconify/types@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@iconify/types/-/types-2.0.0.tgz#ab0e9ea681d6c8a1214f30cd741fe3a20cc57f57" + integrity sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg== + +"@iconify/utils@^2.1.32": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@iconify/utils/-/utils-2.2.1.tgz#635b9bd8fd3e5e53742471bc0b5291f1570dda41" + integrity sha512-0/7J7hk4PqXmxo5PDBDxmnecw5PxklZJfNjIVG9FM0mEfVrvfudS22rYWsqVk6gR3UJ/mSYS90X4R3znXnqfNA== + dependencies: + "@antfu/install-pkg" "^0.4.1" + "@antfu/utils" "^0.7.10" + "@iconify/types" "^2.0.0" + debug "^4.4.0" + globals "^15.13.0" + kolorist "^1.8.0" + local-pkg "^0.5.1" + mlly "^1.7.3" + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -361,10 +430,17 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@next/env@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.15.tgz#06d984e37e670d93ddd6790af1844aeb935f332f" - integrity sha512-S1qaj25Wru2dUpcIZMjxeMVSwkt8BK4dmWHHiBuRstcIyOsMapqT4A4jSB6onvqeygkSSmOkyny9VVx8JIGamQ== +"@mermaid-js/parser@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@mermaid-js/parser/-/parser-0.3.0.tgz#7a28714599f692f93df130b299fa1aadc9f9c8ab" + integrity sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA== + dependencies: + langium "3.0.0" + +"@next/env@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.21.tgz#09ff0813d29c596397e141205d4f5fd5c236bdd0" + integrity sha512-lXcwcJd5oR01tggjWJ6SrNNYFGuOOMB9c251wUNkjCpkoXOPkDeF/15c3mnVlBqrW4JJXb2kVxDFhC4GduJt2A== "@next/eslint-plugin-next@14.2.3": version "14.2.3" @@ -373,50 +449,50 @@ dependencies: glob "10.3.10" -"@next/swc-darwin-arm64@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.15.tgz#6386d585f39a1c490c60b72b1f76612ba4434347" - integrity sha512-Rvh7KU9hOUBnZ9TJ28n2Oa7dD9cvDBKua9IKx7cfQQ0GoYUwg9ig31O2oMwH3wm+pE3IkAQ67ZobPfEgurPZIA== +"@next/swc-darwin-arm64@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.21.tgz#32a31992aace1440981df9cf7cb3af7845d94fec" + integrity sha512-HwEjcKsXtvszXz5q5Z7wCtrHeTTDSTgAbocz45PHMUjU3fBYInfvhR+ZhavDRUYLonm53aHZbB09QtJVJj8T7g== -"@next/swc-darwin-x64@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.15.tgz#b7baeedc6a28f7545ad2bc55adbab25f7b45cb89" - integrity sha512-5TGyjFcf8ampZP3e+FyCax5zFVHi+Oe7sZyaKOngsqyaNEpOgkKB3sqmymkZfowy3ufGA/tUgDPPxpQx931lHg== +"@next/swc-darwin-x64@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.21.tgz#5ab4b3f6685b6b52f810d0f5cf6e471480ddffdb" + integrity sha512-TSAA2ROgNzm4FhKbTbyJOBrsREOMVdDIltZ6aZiKvCi/v0UwFmwigBGeqXDA97TFMpR3LNNpw52CbVelkoQBxA== -"@next/swc-linux-arm64-gnu@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.15.tgz#fa13c59d3222f70fb4cb3544ac750db2c6e34d02" - integrity sha512-3Bwv4oc08ONiQ3FiOLKT72Q+ndEMyLNsc/D3qnLMbtUYTQAmkx9E/JRu0DBpHxNddBmNT5hxz1mYBphJ3mfrrw== +"@next/swc-linux-arm64-gnu@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.21.tgz#8a0e1fa887aef19ca218af2af515d0a5ee67ba3f" + integrity sha512-0Dqjn0pEUz3JG+AImpnMMW/m8hRtl1GQCNbO66V1yp6RswSTiKmnHf3pTX6xMdJYSemf3O4Q9ykiL0jymu0TuA== -"@next/swc-linux-arm64-musl@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.15.tgz#30e45b71831d9a6d6d18d7ac7d611a8d646a17f9" - integrity sha512-k5xf/tg1FBv/M4CMd8S+JL3uV9BnnRmoe7F+GWC3DxkTCD9aewFRH1s5rJ1zkzDa+Do4zyN8qD0N8c84Hu96FQ== +"@next/swc-linux-arm64-musl@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.21.tgz#ddad844406b42fa8965fe11250abc85c1fe0fd05" + integrity sha512-Ggfw5qnMXldscVntwnjfaQs5GbBbjioV4B4loP+bjqNEb42fzZlAaK+ldL0jm2CTJga9LynBMhekNfV8W4+HBw== -"@next/swc-linux-x64-gnu@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.15.tgz#5065db17fc86f935ad117483f21f812dc1b39254" - integrity sha512-kE6q38hbrRbKEkkVn62reLXhThLRh6/TvgSP56GkFNhU22TbIrQDEMrO7j0IcQHcew2wfykq8lZyHFabz0oBrA== +"@next/swc-linux-x64-gnu@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.21.tgz#db55fd666f9ba27718f65caa54b622a912cdd16b" + integrity sha512-uokj0lubN1WoSa5KKdThVPRffGyiWlm/vCc/cMkWOQHw69Qt0X1o3b2PyLLx8ANqlefILZh1EdfLRz9gVpG6tg== -"@next/swc-linux-x64-musl@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.15.tgz#3c4a4568d8be7373a820f7576cf33388b5dab47e" - integrity sha512-PZ5YE9ouy/IdO7QVJeIcyLn/Rc4ml9M2G4y3kCM9MNf1YKvFY4heg3pVa/jQbMro+tP6yc4G2o9LjAz1zxD7tQ== +"@next/swc-linux-x64-musl@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.21.tgz#dddb850353624efcd58c4c4e30ad8a1aab379642" + integrity sha512-iAEBPzWNbciah4+0yI4s7Pce6BIoxTQ0AGCkxn/UBuzJFkYyJt71MadYQkjPqCQCJAFQ26sYh7MOKdU+VQFgPg== -"@next/swc-win32-arm64-msvc@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.15.tgz#fb812cc4ca0042868e32a6a021da91943bb08b98" - integrity sha512-2raR16703kBvYEQD9HNLyb0/394yfqzmIeyp2nDzcPV4yPjqNUG3ohX6jX00WryXz6s1FXpVhsCo3i+g4RUX+g== +"@next/swc-win32-arm64-msvc@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.21.tgz#290012ee57b196d3d2d04853e6bf0179cae9fbaf" + integrity sha512-plykgB3vL2hB4Z32W3ktsfqyuyGAPxqwiyrAi2Mr8LlEUhNn9VgkiAl5hODSBpzIfWweX3er1f5uNpGDygfQVQ== -"@next/swc-win32-ia32-msvc@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.15.tgz#ec26e6169354f8ced240c1427be7fd485c5df898" - integrity sha512-fyTE8cklgkyR1p03kJa5zXEaZ9El+kDNM5A+66+8evQS5e/6v0Gk28LqA0Jet8gKSOyP+OTm/tJHzMlGdQerdQ== +"@next/swc-win32-ia32-msvc@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.21.tgz#c959135a78cab18cca588d11d1e33bcf199590d4" + integrity sha512-w5bacz4Vxqrh06BjWgua3Yf7EMDb8iMcVhNrNx8KnJXt8t+Uu0Zg4JHLDL/T7DkTCEEfKXO/Er1fcfWxn2xfPA== -"@next/swc-win32-x64-msvc@14.2.15": - version "14.2.15" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.15.tgz#18d68697002b282006771f8d92d79ade9efd35c4" - integrity sha512-SzqGbsLsP9OwKNUG9nekShTwhj6JSB9ZLMWQ8g1gG6hdE5gQLncbnbymrwy2yVmH9nikSLYRYxYMFu78Ggp7/g== +"@next/swc-win32-x64-msvc@14.2.21": + version "14.2.21" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.21.tgz#21ff892286555b90538a7d1b505ea21a005d6ead" + integrity sha512-sT6+llIkzpsexGYZq8cjjthRyRGe5cJVhqh12FmlbxHqna6zsDDK8UNaV7g41T6atFHCJUPeLb3uyAwrBwy0NA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1114,6 +1190,216 @@ mkdirp "^2.1.6" path-browserify "^1.0.1" +"@types/d3-array@*": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5" + integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg== + +"@types/d3-axis@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-3.0.6.tgz#e760e5765b8188b1defa32bc8bb6062f81e4c795" + integrity sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-brush@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-3.0.6.tgz#c2f4362b045d472e1b186cdbec329ba52bdaee6c" + integrity sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-chord@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-3.0.6.tgz#1706ca40cf7ea59a0add8f4456efff8f8775793d" + integrity sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg== + +"@types/d3-color@*": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2" + integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A== + +"@types/d3-contour@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-3.0.6.tgz#9ada3fa9c4d00e3a5093fed0356c7ab929604231" + integrity sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg== + dependencies: + "@types/d3-array" "*" + "@types/geojson" "*" + +"@types/d3-delaunay@*": + version "6.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz#185c1a80cc807fdda2a3fe960f7c11c4a27952e1" + integrity sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw== + +"@types/d3-dispatch@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz#096efdf55eb97480e3f5621ff9a8da552f0961e7" + integrity sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ== + +"@types/d3-drag@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.7.tgz#b13aba8b2442b4068c9a9e6d1d82f8bcea77fc02" + integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-dsv@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-3.0.7.tgz#0a351f996dc99b37f4fa58b492c2d1c04e3dac17" + integrity sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g== + +"@types/d3-ease@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b" + integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA== + +"@types/d3-fetch@*": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-3.0.7.tgz#c04a2b4f23181aa376f30af0283dbc7b3b569980" + integrity sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA== + dependencies: + "@types/d3-dsv" "*" + +"@types/d3-force@*": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-3.0.10.tgz#6dc8fc6e1f35704f3b057090beeeb7ac674bff1a" + integrity sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw== + +"@types/d3-format@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-format/-/d3-format-3.0.4.tgz#b1e4465644ddb3fdf3a263febb240a6cd616de90" + integrity sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g== + +"@types/d3-geo@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-3.1.0.tgz#b9e56a079449174f0a2c8684a9a4df3f60522440" + integrity sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ== + dependencies: + "@types/geojson" "*" + +"@types/d3-hierarchy@*": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz#6023fb3b2d463229f2d680f9ac4b47466f71f17b" + integrity sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg== + +"@types/d3-interpolate@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c" + integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== + dependencies: + "@types/d3-color" "*" + +"@types/d3-path@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.1.0.tgz#2b907adce762a78e98828f0b438eaca339ae410a" + integrity sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ== + +"@types/d3-polygon@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-polygon/-/d3-polygon-3.0.2.tgz#dfae54a6d35d19e76ac9565bcb32a8e54693189c" + integrity sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA== + +"@types/d3-quadtree@*": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz#d4740b0fe35b1c58b66e1488f4e7ed02952f570f" + integrity sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg== + +"@types/d3-random@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-3.0.3.tgz#ed995c71ecb15e0cd31e22d9d5d23942e3300cfb" + integrity sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ== + +"@types/d3-scale-chromatic@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#dc6d4f9a98376f18ea50bad6c39537f1b5463c39" + integrity sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ== + +"@types/d3-scale@*": + version "4.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.8.tgz#d409b5f9dcf63074464bf8ddfb8ee5a1f95945bb" + integrity sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ== + dependencies: + "@types/d3-time" "*" + +"@types/d3-selection@*": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.11.tgz#bd7a45fc0a8c3167a631675e61bc2ca2b058d4a3" + integrity sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w== + +"@types/d3-shape@*": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.7.tgz#2b7b423dc2dfe69c8c93596e673e37443348c555" + integrity sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg== + dependencies: + "@types/d3-path" "*" + +"@types/d3-time-format@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-4.0.3.tgz#d6bc1e6b6a7db69cccfbbdd4c34b70632d9e9db2" + integrity sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg== + +"@types/d3-time@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.4.tgz#8472feecd639691450dd8000eb33edd444e1323f" + integrity sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g== + +"@types/d3-timer@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70" + integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw== + +"@types/d3-transition@*": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.9.tgz#1136bc57e9ddb3c390dccc9b5ff3b7d2b8d94706" + integrity sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg== + dependencies: + "@types/d3-selection" "*" + +"@types/d3-zoom@*": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz#dccb32d1c56b1e1c6e0f1180d994896f038bc40b" + integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw== + dependencies: + "@types/d3-interpolate" "*" + "@types/d3-selection" "*" + +"@types/d3@^7.4.3": + version "7.4.3" + resolved "https://registry.yarnpkg.com/@types/d3/-/d3-7.4.3.tgz#d4550a85d08f4978faf0a4c36b848c61eaac07e2" + integrity sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww== + dependencies: + "@types/d3-array" "*" + "@types/d3-axis" "*" + "@types/d3-brush" "*" + "@types/d3-chord" "*" + "@types/d3-color" "*" + "@types/d3-contour" "*" + "@types/d3-delaunay" "*" + "@types/d3-dispatch" "*" + "@types/d3-drag" "*" + "@types/d3-dsv" "*" + "@types/d3-ease" "*" + "@types/d3-fetch" "*" + "@types/d3-force" "*" + "@types/d3-format" "*" + "@types/d3-geo" "*" + "@types/d3-hierarchy" "*" + "@types/d3-interpolate" "*" + "@types/d3-path" "*" + "@types/d3-polygon" "*" + "@types/d3-quadtree" "*" + "@types/d3-random" "*" + "@types/d3-scale" "*" + "@types/d3-scale-chromatic" "*" + "@types/d3-selection" "*" + "@types/d3-shape" "*" + "@types/d3-time" "*" + "@types/d3-time-format" "*" + "@types/d3-timer" "*" + "@types/d3-transition" "*" + "@types/d3-zoom" "*" + "@types/dompurify@^3.0.5": version "3.2.0" resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-3.2.0.tgz#56610bf3e4250df57744d61fbd95422e07dfb840" @@ -1121,6 +1407,11 @@ dependencies: dompurify "*" +"@types/geojson@*": + version "7946.0.15" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.15.tgz#f9d55fd5a0aa2de9dc80b1b04e437538b7298868" + integrity sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA== + "@types/intl-tel-input@^18.1.4": version "18.1.4" resolved "https://registry.yarnpkg.com/@types/intl-tel-input/-/intl-tel-input-18.1.4.tgz#0eb5211a7490f8a8d7aa940ee594a85138d514c9" @@ -1254,7 +1545,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.9.0: +acorn@^8.14.0, acorn@^8.9.0: version "8.14.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== @@ -1602,6 +1893,25 @@ chalk@^5.0.0, chalk@~5.3.0: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== +chevrotain-allstar@~0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz#b7412755f5d83cc139ab65810cdb00d8db40e6ca" + integrity sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw== + dependencies: + lodash-es "^4.17.21" + +chevrotain@~11.0.3: + version "11.0.3" + resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-11.0.3.tgz#88ffc1fb4b5739c715807eaeedbbf200e202fc1b" + integrity sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw== + dependencies: + "@chevrotain/cst-dts-gen" "11.0.3" + "@chevrotain/gast" "11.0.3" + "@chevrotain/regexp-to-ast" "11.0.3" + "@chevrotain/types" "11.0.3" + "@chevrotain/utils" "11.0.3" + lodash-es "4.17.21" + chokidar@^3.5.2, chokidar@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" @@ -1703,6 +2013,11 @@ colorette@^2.0.20: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +commander@7: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + commander@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" @@ -1728,11 +2043,30 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +cose-base@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-1.0.3.tgz#650334b41b869578a543358b80cda7e0abe0a60a" + integrity sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg== + dependencies: + layout-base "^1.0.0" + +cose-base@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cose-base/-/cose-base-2.2.0.tgz#1c395c35b6e10bb83f9769ca8b817d614add5c01" + integrity sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g== + dependencies: + layout-base "^2.0.0" + cosmiconfig@^8.1.3: version "8.3.6" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" @@ -1767,6 +2101,304 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +cytoscape-cose-bilkent@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz#762fa121df9930ffeb51a495d87917c570ac209b" + integrity sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ== + dependencies: + cose-base "^1.0.0" + +cytoscape-fcose@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz#e4d6f6490df4fab58ae9cea9e5c3ab8d7472f471" + integrity sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ== + dependencies: + cose-base "^2.2.0" + +cytoscape@^3.29.2: + version "3.30.4" + resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.30.4.tgz#3404da0a159c00a1a3df2c85b2b43fdc66a0e28e" + integrity sha512-OxtlZwQl1WbwMmLiyPSEBuzeTIQnwZhJYYWFzZ2PhEHVFwpeaqNIkUzSiso00D98qk60l8Gwon2RP304d3BJ1A== + +"d3-array@1 - 2": + version "2.12.1" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" + integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== + dependencies: + internmap "^1.0.0" + +"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" + integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== + dependencies: + internmap "1 - 2" + +d3-axis@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322" + integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw== + +d3-brush@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c" + integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "3" + d3-transition "3" + +d3-chord@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-3.0.1.tgz#d156d61f485fce8327e6abf339cb41d8cbba6966" + integrity sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g== + dependencies: + d3-path "1 - 3" + +"d3-color@1 - 3", d3-color@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + +d3-contour@4: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-4.0.2.tgz#bb92063bc8c5663acb2422f99c73cbb6c6ae3bcc" + integrity sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA== + dependencies: + d3-array "^3.2.0" + +d3-delaunay@6: + version "6.0.4" + resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-6.0.4.tgz#98169038733a0a5babbeda55054f795bb9e4a58b" + integrity sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A== + dependencies: + delaunator "5" + +"d3-dispatch@1 - 3", d3-dispatch@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== + +"d3-drag@2 - 3", d3-drag@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" + integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== + dependencies: + d3-dispatch "1 - 3" + d3-selection "3" + +"d3-dsv@1 - 3", d3-dsv@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73" + integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q== + dependencies: + commander "7" + iconv-lite "0.6" + rw "1" + +"d3-ease@1 - 3", d3-ease@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +d3-fetch@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-3.0.1.tgz#83141bff9856a0edb5e38de89cdcfe63d0a60a22" + integrity sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw== + dependencies: + d3-dsv "1 - 3" + +d3-force@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4" + integrity sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg== + dependencies: + d3-dispatch "1 - 3" + d3-quadtree "1 - 3" + d3-timer "1 - 3" + +"d3-format@1 - 3", d3-format@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" + integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== + +d3-geo@3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-3.1.1.tgz#6027cf51246f9b2ebd64f99e01dc7c3364033a4d" + integrity sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q== + dependencies: + d3-array "2.5.0 - 3" + +d3-hierarchy@3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6" + integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA== + +"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +d3-path@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" + integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== + +"d3-path@1 - 3", d3-path@3, d3-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" + integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== + +d3-polygon@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-3.0.1.tgz#0b45d3dd1c48a29c8e057e6135693ec80bf16398" + integrity sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg== + +"d3-quadtree@1 - 3", d3-quadtree@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f" + integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw== + +d3-random@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4" + integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ== + +d3-sankey@^0.12.3: + version "0.12.3" + resolved "https://registry.yarnpkg.com/d3-sankey/-/d3-sankey-0.12.3.tgz#b3c268627bd72e5d80336e8de6acbfec9d15d01d" + integrity sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ== + dependencies: + d3-array "1 - 2" + d3-shape "^1.2.0" + +d3-scale-chromatic@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#34c39da298b23c20e02f1a4b239bd0f22e7f1314" + integrity sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ== + dependencies: + d3-color "1 - 3" + d3-interpolate "1 - 3" + +d3-scale@4: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" + integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== + dependencies: + d3-array "2.10.0 - 3" + d3-format "1 - 3" + d3-interpolate "1.2.0 - 3" + d3-time "2.1.1 - 3" + d3-time-format "2 - 4" + +"d3-selection@2 - 3", d3-selection@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" + integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== + +d3-shape@3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" + integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== + dependencies: + d3-path "^3.1.0" + +d3-shape@^1.2.0: + version "1.3.7" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" + integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== + dependencies: + d3-path "1" + +"d3-time-format@2 - 4", d3-time-format@4: + version "4.1.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== + dependencies: + d3-time "1 - 3" + +"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" + integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== + dependencies: + d3-array "2 - 3" + +"d3-timer@1 - 3", d3-timer@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +"d3-transition@2 - 3", d3-transition@3: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" + integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== + dependencies: + d3-color "1 - 3" + d3-dispatch "1 - 3" + d3-ease "1 - 3" + d3-interpolate "1 - 3" + d3-timer "1 - 3" + +d3-zoom@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" + integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "2 - 3" + d3-transition "2 - 3" + +d3@^7.9.0: + version "7.9.0" + resolved "https://registry.yarnpkg.com/d3/-/d3-7.9.0.tgz#579e7acb3d749caf8860bd1741ae8d371070cd5d" + integrity sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA== + dependencies: + d3-array "3" + d3-axis "3" + d3-brush "3" + d3-chord "3" + d3-color "3" + d3-contour "4" + d3-delaunay "6" + d3-dispatch "3" + d3-drag "3" + d3-dsv "3" + d3-ease "3" + d3-fetch "3" + d3-force "3" + d3-format "3" + d3-geo "3" + d3-hierarchy "3" + d3-interpolate "3" + d3-path "3" + d3-polygon "3" + d3-quadtree "3" + d3-random "3" + d3-scale "4" + d3-scale-chromatic "3" + d3-selection "3" + d3-shape "3" + d3-time "3" + d3-time-format "4" + d3-timer "3" + d3-transition "3" + d3-zoom "3" + +dagre-d3-es@7.0.11: + version "7.0.11" + resolved "https://registry.yarnpkg.com/dagre-d3-es/-/dagre-d3-es-7.0.11.tgz#2237e726c0577bfe67d1a7cfd2265b9ab2c15c40" + integrity sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw== + dependencies: + d3 "^7.9.0" + lodash-es "^4.17.21" + damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -1804,7 +2436,12 @@ data-view-byte-offset@^1.0.0: es-errors "^1.3.0" is-data-view "^1.0.1" -debug@4, debug@^4, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@~4.4.0: +dayjs@^1.11.10: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + +debug@4, debug@^4, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@^4.4.0, debug@~4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== @@ -1848,6 +2485,13 @@ define-properties@^1.1.3, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +delaunator@5: + version "5.0.1" + resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.1.tgz#39032b08053923e924d6094fe2cde1a99cc51278" + integrity sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw== + dependencies: + robust-predicates "^3.0.2" + detect-node-es@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" @@ -1889,7 +2533,7 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dompurify@*, dompurify@^3.1.6: +dompurify@*, dompurify@^3.1.6, dompurify@^3.2.1: version "3.2.3" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.2.3.tgz#05dd2175225324daabfca6603055a09b2382a4cd" integrity sha512-U1U5Hzc2MO0oW3DF+G9qYN0aT7atAou4AgI0XjWz061nyBPbdxkfdhfy5uMgGn6+oLFCfn44ZGbdDqCzVmlOWA== @@ -2635,6 +3279,11 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" +globals@^15.13.0: + version "15.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.14.0.tgz#b8fd3a8941ff3b4d38f3319d433b61bbb482e73f" + integrity sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig== + globalthis@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" @@ -2670,6 +3319,11 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +hachure-fill@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/hachure-fill/-/hachure-fill-0.5.2.tgz#d19bc4cc8750a5962b47fb1300557a85fcf934cc" + integrity sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg== + has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -2746,6 +3400,13 @@ husky@^9.0.11: resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.7.tgz#d46a38035d101b46a70456a850ff4201344c0b2d" integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA== +iconv-lite@0.6: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -2801,6 +3462,16 @@ internal-slot@^1.0.7, internal-slot@^1.1.0: hasown "^2.0.2" side-channel "^1.1.0" +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== + +internmap@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" + integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== + intl-tel-input@^23.8.1: version "23.9.3" resolved "https://registry.yarnpkg.com/intl-tel-input/-/intl-tel-input-23.9.3.tgz#3870c78c16655bdc13e18cae557efcaa43dce719" @@ -3150,10 +3821,17 @@ jsonfile@^6.0.1: object.assign "^4.1.4" object.values "^1.1.6" -katex@^0.16.10: - version "0.16.17" - resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.17.tgz#72c588a0beca0cac10c30f447c2fb14647f773ed" - integrity sha512-OyzSrXBllz+Jdc9Auiw0kt21gbZ4hkz8Q5srVAb2U9INcYIfGKbxe+bvNvEz1bQ/NrDeRRho5eLCyk/L03maAw== +katex@^0.16.21: + version "0.16.21" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.21.tgz#8f63c659e931b210139691f2cc7bb35166b792a3" + integrity sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A== + dependencies: + commander "^8.3.0" + +katex@^0.16.9: + version "0.16.19" + resolved "https://registry.yarnpkg.com/katex/-/katex-0.16.19.tgz#698e026188876f9c8c93d3ecb27b212aaa056d0a" + integrity sha512-3IA6DYVhxhBabjSLTNO9S4+OliA3Qvb8pBQXMfC4WxXJgLwZgnfDl0BmB4z6nBMdznBsZ+CGM8DrGZ5hcguDZg== dependencies: commander "^8.3.0" @@ -3164,11 +3842,32 @@ keyv@^4.5.3: dependencies: json-buffer "3.0.1" +khroma@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/khroma/-/khroma-2.1.0.tgz#45f2ce94ce231a437cf5b63c2e886e6eb42bbbb1" + integrity sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw== + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +kolorist@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + +langium@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/langium/-/langium-3.0.0.tgz#4938294eb57c59066ef955070ac4d0c917b26026" + integrity sha512-+Ez9EoiByeoTu/2BXmEaZ06iPNXM6thWJp02KfBO/raSMyCJ4jw7AkWWa+zBCTm0+Tw1Fj9FOxdqSskyN5nAwg== + dependencies: + chevrotain "~11.0.3" + chevrotain-allstar "~0.3.0" + vscode-languageserver "~9.0.1" + vscode-languageserver-textdocument "~1.0.11" + vscode-uri "~3.0.8" + language-subtag-registry@^0.3.20: version "0.3.23" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" @@ -3181,6 +3880,16 @@ language-tags@^1.0.9: dependencies: language-subtag-registry "^0.3.20" +layout-base@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-1.0.2.tgz#1291e296883c322a9dd4c5dd82063721b53e26e2" + integrity sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg== + +layout-base@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/layout-base/-/layout-base-2.0.1.tgz#d0337913586c90f9c2c075292069f5c2da5dd285" + integrity sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg== + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -3239,6 +3948,14 @@ listr2@~8.2.5: rfdc "^1.4.1" wrap-ansi "^9.0.0" +local-pkg@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.1.tgz#69658638d2a95287534d4c2fff757980100dbb6d" + integrity sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ== + dependencies: + mlly "^1.7.3" + pkg-types "^1.2.1" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -3246,6 +3963,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash-es@4.17.21, lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -3318,6 +4040,11 @@ markdown-it@^14.1.0: punycode.js "^2.3.1" uc.micro "^2.1.0" +marked@^13.0.2: + version "13.0.3" + resolved "https://registry.yarnpkg.com/marked/-/marked-13.0.3.tgz#5c5b4a5d0198060c7c9bc6ef9420a7fed30f822d" + integrity sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA== + math-intrinsics@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.0.0.tgz#4e04bf87c85aa51e90d078dac2252b4eb5260817" @@ -3338,6 +4065,32 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +mermaid@^11.4.1: + version "11.4.1" + resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-11.4.1.tgz#577fad5c31a01a06d9f793e298d411f1379eecc8" + integrity sha512-Mb01JT/x6CKDWaxigwfZYuYmDZ6xtrNwNlidKZwkSrDaY9n90tdrJTV5Umk+wP1fZscGptmKFXHsXMDEVZ+Q6A== + dependencies: + "@braintree/sanitize-url" "^7.0.1" + "@iconify/utils" "^2.1.32" + "@mermaid-js/parser" "^0.3.0" + "@types/d3" "^7.4.3" + cytoscape "^3.29.2" + cytoscape-cose-bilkent "^4.1.0" + cytoscape-fcose "^2.2.0" + d3 "^7.9.0" + d3-sankey "^0.12.3" + dagre-d3-es "7.0.11" + dayjs "^1.11.10" + dompurify "^3.2.1" + katex "^0.16.9" + khroma "^2.1.0" + lodash-es "^4.17.21" + marked "^13.0.2" + roughjs "^4.6.6" + stylis "^4.3.1" + ts-dedent "^2.2.0" + uuid "^9.0.1" + micromatch@^4.0.4, micromatch@^4.0.8, micromatch@~4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" @@ -3404,6 +4157,16 @@ mkdirp@^2.1.6: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== +mlly@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.3.tgz#d86c0fcd8ad8e16395eb764a5f4b831590cee48c" + integrity sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A== + dependencies: + acorn "^8.14.0" + pathe "^1.1.2" + pkg-types "^1.2.1" + ufo "^1.5.4" + ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -3428,12 +4191,12 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -next@14.2.15: - version "14.2.15" - resolved "https://registry.yarnpkg.com/next/-/next-14.2.15.tgz#348e5603e22649775d19c785c09a89c9acb5189a" - integrity sha512-h9ctmOokpoDphRvMGnwOJAedT6zKhwqyZML9mDtspgf4Rh3Pn7UTYKqePNoDvhsWBAO5GoPNYshnAUGIazVGmw== +next@14.2.21: + version "14.2.21" + resolved "https://registry.yarnpkg.com/next/-/next-14.2.21.tgz#f6da9e2abba1a0e4ca7a5273825daf06632554ba" + integrity sha512-rZmLwucLHr3/zfDMYbJXbw0ZeoBpirxkXuvsJbk7UPorvPYZhP7vq7aHbKnU7dQNCYIimRrbB2pp3xmf+wsYUg== dependencies: - "@next/env" "14.2.15" + "@next/env" "14.2.21" "@swc/helpers" "0.5.5" busboy "1.6.0" caniuse-lite "^1.0.30001579" @@ -3441,15 +4204,15 @@ next@14.2.15: postcss "8.4.31" styled-jsx "5.1.1" optionalDependencies: - "@next/swc-darwin-arm64" "14.2.15" - "@next/swc-darwin-x64" "14.2.15" - "@next/swc-linux-arm64-gnu" "14.2.15" - "@next/swc-linux-arm64-musl" "14.2.15" - "@next/swc-linux-x64-gnu" "14.2.15" - "@next/swc-linux-x64-musl" "14.2.15" - "@next/swc-win32-arm64-msvc" "14.2.15" - "@next/swc-win32-ia32-msvc" "14.2.15" - "@next/swc-win32-x64-msvc" "14.2.15" + "@next/swc-darwin-arm64" "14.2.21" + "@next/swc-darwin-x64" "14.2.21" + "@next/swc-linux-arm64-gnu" "14.2.21" + "@next/swc-linux-arm64-musl" "14.2.21" + "@next/swc-linux-x64-gnu" "14.2.21" + "@next/swc-linux-x64-musl" "14.2.21" + "@next/swc-win32-arm64-msvc" "14.2.21" + "@next/swc-win32-ia32-msvc" "14.2.21" + "@next/swc-win32-x64-msvc" "14.2.21" node-domexception@^1.0.0: version "1.0.0" @@ -3644,6 +4407,11 @@ package-json-from-dist@^1.0.0: resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== +package-manager-detector@^0.2.0: + version "0.2.8" + resolved "https://registry.yarnpkg.com/package-manager-detector/-/package-manager-detector-0.2.8.tgz#f5ace2dbd37666af54e5acec11bc37c8450f72d0" + integrity sha512-ts9KSdroZisdvKMWVAVCXiKqnqNfXz4+IbrBG8/BWx/TR5le+jfenvoBuIZ6UWM9nz47W7AbD9qYfAwfWMIwzA== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3666,6 +4434,11 @@ path-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== +path-data-parser@0.1.0, path-data-parser@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/path-data-parser/-/path-data-parser-0.1.0.tgz#8f5ba5cc70fc7becb3dcefaea08e2659aba60b8c" + integrity sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w== + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -3704,6 +4477,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pathe@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" + integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== + picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" @@ -3729,6 +4507,28 @@ pirates@^4.0.1: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== +pkg-types@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.0.tgz#53d915eb99485798c554ad8eb2dc2af7c03006eb" + integrity sha512-kS7yWjVFCkIw9hqdJBoMxDdzEngmkr5FXeWZZfQ6GoYacjVnsW6l2CcYW/0ThD0vF4LPJgVYnrg4d0uuhwYQbg== + dependencies: + confbox "^0.1.8" + mlly "^1.7.3" + pathe "^1.1.2" + +points-on-curve@0.2.0, points-on-curve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/points-on-curve/-/points-on-curve-0.2.0.tgz#7dbb98c43791859434284761330fa893cb81b4d1" + integrity sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A== + +points-on-path@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/points-on-path/-/points-on-path-0.2.1.tgz#553202b5424c53bed37135b318858eacff85dd52" + integrity sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g== + dependencies: + path-data-parser "0.1.0" + points-on-curve "0.2.0" + possible-typed-array-names@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" @@ -4021,6 +4821,21 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +robust-predicates@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771" + integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== + +roughjs@^4.6.6: + version "4.6.6" + resolved "https://registry.yarnpkg.com/roughjs/-/roughjs-4.6.6.tgz#1059f49a5e0c80dee541a005b20cc322b222158b" + integrity sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ== + dependencies: + hachure-fill "^0.5.2" + path-data-parser "^0.1.0" + points-on-curve "^0.2.0" + points-on-path "^0.2.1" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -4028,6 +4843,11 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rw@1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" + integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== + safe-array-concat@^1.1.2, safe-array-concat@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" @@ -4053,6 +4873,11 @@ safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + scheduler@^0.23.2: version "0.23.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" @@ -4383,6 +5208,11 @@ styled-jsx@5.1.1: dependencies: client-only "0.0.1" +stylis@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.4.tgz#ca5c6c4a35c4784e4e93a2a24dc4e9fa075250a4" + integrity sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now== + sucrase@^3.35.0: version "3.35.0" resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" @@ -4498,6 +5328,11 @@ tiny-invariant@^1.3.3: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== +tinyexec@^0.3.0: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -4515,6 +5350,11 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== +ts-dedent@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" + integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== + ts-interface-checker@^0.1.9: version "0.1.13" resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" @@ -4619,6 +5459,11 @@ uc.micro@^2.0.0, uc.micro@^2.1.0: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== +ufo@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754" + integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== + unbox-primitive@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" @@ -4684,6 +5529,11 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + vaul@^0.9.1: version "0.9.9" resolved "https://registry.yarnpkg.com/vaul/-/vaul-0.9.9.tgz#ff075c3cba6193d4859bb6f1b09efcce049cf812" @@ -4691,6 +5541,41 @@ vaul@^0.9.1: dependencies: "@radix-ui/react-dialog" "^1.1.1" +vscode-jsonrpc@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz#f43dfa35fb51e763d17cd94dcca0c9458f35abf9" + integrity sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA== + +vscode-languageserver-protocol@3.17.5: + version "3.17.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz#864a8b8f390835572f4e13bd9f8313d0e3ac4bea" + integrity sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg== + dependencies: + vscode-jsonrpc "8.2.0" + vscode-languageserver-types "3.17.5" + +vscode-languageserver-textdocument@~1.0.11: + version "1.0.12" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz#457ee04271ab38998a093c68c2342f53f6e4a631" + integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA== + +vscode-languageserver-types@3.17.5: + version "3.17.5" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a" + integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg== + +vscode-languageserver@~9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz#500aef82097eb94df90d008678b0b6b5f474015b" + integrity sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g== + dependencies: + vscode-languageserver-protocol "3.17.5" + +vscode-uri@~3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.8.tgz#1770938d3e72588659a172d0fd4642780083ff9f" + integrity sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw== + wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" diff --git a/src/khoj/configure.py b/src/khoj/configure.py index 06b5b497..98fb41a0 100644 --- a/src/khoj/configure.py +++ b/src/khoj/configure.py @@ -234,7 +234,7 @@ def configure_server( if ConversationAdapters.has_valid_ai_model_api(): ai_model_api = ConversationAdapters.get_ai_model_api() - state.openai_client = openai.OpenAI(api_key=ai_model_api.api_key) + state.openai_client = openai.OpenAI(api_key=ai_model_api.api_key, base_url=ai_model_api.api_base_url) # Initialize Search Models from Config and initialize content try: @@ -249,6 +249,7 @@ def configure_server( model.bi_encoder, model.embeddings_inference_endpoint, model.embeddings_inference_endpoint_api_key, + model.embeddings_inference_endpoint_type, query_encode_kwargs=model.bi_encoder_query_encode_config, docs_encode_kwargs=model.bi_encoder_docs_encode_config, model_kwargs=model.bi_encoder_model_config, diff --git a/src/khoj/database/adapters/__init__.py b/src/khoj/database/adapters/__init__.py index 33c1c6b8..2cd9daf7 100644 --- a/src/khoj/database/adapters/__init__.py +++ b/src/khoj/database/adapters/__init__.py @@ -1288,7 +1288,7 @@ class ConversationAdapters: @staticmethod async def get_speech_to_text_config(): - return await SpeechToTextModelOptions.objects.filter().afirst() + return await SpeechToTextModelOptions.objects.filter().prefetch_related("ai_model_api").afirst() @staticmethod @arequire_valid_user diff --git a/src/khoj/database/admin.py b/src/khoj/database/admin.py index a90a339e..322b3afd 100644 --- a/src/khoj/database/admin.py +++ b/src/khoj/database/admin.py @@ -1,6 +1,7 @@ import csv import json from datetime import datetime, timedelta +from urllib.parse import quote from apscheduler.job import Job from django.contrib import admin, messages @@ -154,8 +155,9 @@ class KhojUserAdmin(UserAdmin, unfold_admin.ModelAdmin): for user in queryset: if user.email: host = request.get_host() - unique_id = user.email_verification_code - login_url = f"{host}/auth/magic?code={unique_id}&email={user.email}" + otp = quote(user.email_verification_code) + encoded_email = quote(user.email) + login_url = f"{host}/auth/magic?code={otp}&email={encoded_email}" messages.info(request, f"Email login URL for {user.email}: {login_url}") get_email_login_url.short_description = "Get email login URL" # type: ignore diff --git a/src/khoj/database/management/commands/change_default_model.py b/src/khoj/database/management/commands/change_default_model.py index d55fd44e..43111dd9 100644 --- a/src/khoj/database/management/commands/change_default_model.py +++ b/src/khoj/database/management/commands/change_default_model.py @@ -3,11 +3,11 @@ from typing import List from django.core.management.base import BaseCommand from django.db import transaction -from django.db.models import Count, Q +from django.db.models import Q from tqdm import tqdm from khoj.database.adapters import get_default_search_model -from khoj.database.models import Agent, Entry, KhojUser, SearchModelConfig +from khoj.database.models import Entry, SearchModelConfig from khoj.processor.embeddings import EmbeddingsModel logging.basicConfig(level=logging.INFO) @@ -74,6 +74,7 @@ class Command(BaseCommand): model.bi_encoder, model.embeddings_inference_endpoint, model.embeddings_inference_endpoint_api_key, + model.embeddings_inference_endpoint_type, query_encode_kwargs=model.bi_encoder_query_encode_config, docs_encode_kwargs=model.bi_encoder_docs_encode_config, model_kwargs=model.bi_encoder_model_config, diff --git a/src/khoj/database/migrations/0079_searchmodelconfig_embeddings_inference_endpoint_type.py b/src/khoj/database/migrations/0079_searchmodelconfig_embeddings_inference_endpoint_type.py new file mode 100644 index 00000000..a05668da --- /dev/null +++ b/src/khoj/database/migrations/0079_searchmodelconfig_embeddings_inference_endpoint_type.py @@ -0,0 +1,29 @@ +# Generated by Django 5.0.10 on 2025-01-08 15:09 + +from django.db import migrations, models + + +def set_endpoint_type(apps, schema_editor): + SearchModelConfig = apps.get_model("database", "SearchModelConfig") + SearchModelConfig.objects.filter(embeddings_inference_endpoint__isnull=False).exclude( + embeddings_inference_endpoint="" + ).update(embeddings_inference_endpoint_type="huggingface") + + +class Migration(migrations.Migration): + dependencies = [ + ("database", "0078_khojuser_email_verification_code_expiry"), + ] + + operations = [ + migrations.AddField( + model_name="searchmodelconfig", + name="embeddings_inference_endpoint_type", + field=models.CharField( + choices=[("huggingface", "Huggingface"), ("openai", "Openai"), ("local", "Local")], + default="local", + max_length=200, + ), + ), + migrations.RunPython(set_endpoint_type, reverse_code=migrations.RunPython.noop), + ] diff --git a/src/khoj/database/migrations/0080_speechtotextmodeloptions_ai_model_api.py b/src/khoj/database/migrations/0080_speechtotextmodeloptions_ai_model_api.py new file mode 100644 index 00000000..5ed66e16 --- /dev/null +++ b/src/khoj/database/migrations/0080_speechtotextmodeloptions_ai_model_api.py @@ -0,0 +1,24 @@ +# Generated by Django 5.0.10 on 2025-01-15 11:05 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("database", "0079_searchmodelconfig_embeddings_inference_endpoint_type"), + ] + + operations = [ + migrations.AddField( + model_name="speechtotextmodeloptions", + name="ai_model_api", + field=models.ForeignKey( + blank=True, + default=None, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="database.aimodelapi", + ), + ), + ] diff --git a/src/khoj/database/models/__init__.py b/src/khoj/database/models/__init__.py index c169e55c..7ece32f8 100644 --- a/src/khoj/database/models/__init__.py +++ b/src/khoj/database/models/__init__.py @@ -109,6 +109,7 @@ class ChatMessage(PydanticBaseModel): images: Optional[List[str]] = None queryFiles: Optional[List[Dict]] = None excalidrawDiagram: Optional[List[Dict]] = None + mermaidjsDiagram: str = None by: str turnId: Optional[str] = None intent: Optional[Intent] = None @@ -482,6 +483,11 @@ class SearchModelConfig(DbBaseModel): class ModelType(models.TextChoices): TEXT = "text" + class ApiType(models.TextChoices): + HUGGINGFACE = "huggingface" + OPENAI = "openai" + LOCAL = "local" + # This is the model name exposed to users on their settings page name = models.CharField(max_length=200, default="default") # Type of content the model can generate embeddings for @@ -502,6 +508,10 @@ class SearchModelConfig(DbBaseModel): embeddings_inference_endpoint = models.CharField(max_length=200, default=None, null=True, blank=True) # Inference server API Key to use for embeddings inference. Bi-encoder model should be hosted on this server embeddings_inference_endpoint_api_key = models.CharField(max_length=200, default=None, null=True, blank=True) + # Inference server API type to use for embeddings inference. + embeddings_inference_endpoint_type = models.CharField( + max_length=200, choices=ApiType.choices, default=ApiType.LOCAL + ) # Inference server API endpoint to use for embeddings inference. Cross-encoder model should be hosted on this server cross_encoder_inference_endpoint = models.CharField(max_length=200, default=None, null=True, blank=True) # Inference server API Key to use for embeddings inference. Cross-encoder model should be hosted on this server @@ -558,6 +568,7 @@ class SpeechToTextModelOptions(DbBaseModel): model_name = models.CharField(max_length=200, default="base") model_type = models.CharField(max_length=200, choices=ModelType.choices, default=ModelType.OFFLINE) + ai_model_api = models.ForeignKey(AiModelApi, on_delete=models.CASCADE, default=None, null=True, blank=True) def __str__(self): return f"{self.model_name} - {self.model_type}" diff --git a/src/khoj/processor/conversation/prompts.py b/src/khoj/processor/conversation/prompts.py index e1ed7820..e8ff56c0 100644 --- a/src/khoj/processor/conversation/prompts.py +++ b/src/khoj/processor/conversation/prompts.py @@ -194,7 +194,7 @@ Limit your response to 3 sentences max. Be succinct, clear, and informative. ## Diagram Generation ## -- -improve_diagram_description_prompt = PromptTemplate.from_template( +improve_excalidraw_diagram_description_prompt = PromptTemplate.from_template( """ You are an architect working with a novice digital artist using a diagramming software. {personality_context} @@ -338,6 +338,123 @@ Diagram Description: {query} """.strip() ) +improve_mermaid_js_diagram_description_prompt = PromptTemplate.from_template( + """ +You are a senior architect working with an illustrator using a diagramming software. +{personality_context} + +Given a particular request, you need to translate it to to a detailed description that the illustrator can use to create a diagram. + +You can use the following diagram types in your instructions: +- Flowchart +- Sequence Diagram +- Gantt Chart (only for time-based queries after 0 AD) +- State Diagram +- Pie Chart + +Use these primitives to describe what sort of diagram the drawer should create in natural language, not special syntax. We must recreate the diagram every time, so include all relevant prior information in your description. + +- Describe the layout, components, and connections. +- Use simple, concise language. + +Today's Date: {current_date} +User's Location: {location} + +User's Notes: +{references} + +Online References: +{online_results} + +Conversation Log: +{chat_history} + +Query: {query} + +Enhanced Description: +""".strip() +) + +mermaid_js_diagram_generation_prompt = PromptTemplate.from_template( + """ +You are a designer with the ability to describe diagrams to compose in professional, fine detail. You dive into the details and make labels, connections, and shapes to represent complex systems. +{personality_context} + +----Goals---- +You need to create a declarative description of the diagram and relevant components, using the Mermaid.js syntax. + +You can choose from the following diagram types: +- Flowchart +- Sequence Diagram +- State Diagram +- Gantt Chart +- Pie Chart + +----Examples---- +--- +title: Node +--- + +flowchart LR + id["This is the start"] --> id2["This is the end"] + +sequenceDiagram + Alice->>John: Hello John, how are you? + John-->>Alice: Great! + Alice-)John: See you later! + +stateDiagram-v2 + [*] --> Still + Still --> [*] + + Still --> Moving + Moving --> Still + Moving --> Crash + Crash --> [*] + +gantt + title A Gantt Diagram + dateFormat YYYY-MM-DD + section Section + A task :a1, 2014-01-01, 30d + Another task :after a1, 20d + section Another + Task in Another :2014-01-12, 12d + another task :24d + +pie title Pets adopted by volunteers + "Dogs" : 10 + "Cats" : 30 + "Rats" : 60 + +flowchart TB + subgraph "Group 1" + a1["Start Node"] --> a2["End Node"] + end + subgraph "Group 2" + b1["Process 1"] --> b2["Process 2"] + end + subgraph "Group 3" + c1["Input"] --> c2["Output"] + end + a["Group 1"] --> b["Group 2"] + c["Group 3"] --> d["Group 2"] + +----Process---- +Create your diagram with great composition and intuitiveness from the provided context and user prompt below. +- You may use subgraphs to group elements together. Each subgraph must have a title. +- **You must wrap ALL entity and node labels in double quotes**, example: "My Node Label" +- **All nodes MUST use the id["label"] format**. For example: node1["My Node Label"] +- Custom style are not permitted. Default styles only. +- JUST provide the diagram, no additional text or context. Say nothing else in your response except the diagram. +- Keep diagrams simple - maximum 15 nodes +- Every node inside a subgraph MUST use square bracket notation: id["label"] + +output: {query} + +""".strip() +) + failed_diagram_generation = PromptTemplate.from_template( """ You attempted to programmatically generate a diagram but failed due to a system issue. You are normally able to generate diagrams, but you encountered a system issue this time. diff --git a/src/khoj/processor/conversation/utils.py b/src/khoj/processor/conversation/utils.py index 883650ec..75a76918 100644 --- a/src/khoj/processor/conversation/utils.py +++ b/src/khoj/processor/conversation/utils.py @@ -62,7 +62,7 @@ model_to_prompt_size = { "claude-3-5-sonnet-20241022": 60000, "claude-3-5-haiku-20241022": 60000, # Offline Models - "Qwen/Qwen2.5-14B-Instruct-GGUF": 20000, + "bartowski/Qwen2.5-14B-Instruct-GGUF": 20000, "bartowski/Meta-Llama-3.1-8B-Instruct-GGUF": 20000, "bartowski/Llama-3.2-3B-Instruct-GGUF": 20000, "bartowski/gemma-2-9b-it-GGUF": 6000, @@ -266,7 +266,7 @@ def save_to_conversation_log( raw_query_files: List[FileAttachment] = [], generated_images: List[str] = [], raw_generated_files: List[FileAttachment] = [], - generated_excalidraw_diagram: str = None, + generated_mermaidjs_diagram: str = None, train_of_thought: List[Any] = [], tracer: Dict[str, Any] = {}, ): @@ -290,8 +290,8 @@ def save_to_conversation_log( "queryFiles": [file.model_dump(mode="json") for file in raw_generated_files], } - if generated_excalidraw_diagram: - khoj_message_metadata["excalidrawDiagram"] = generated_excalidraw_diagram + if generated_mermaidjs_diagram: + khoj_message_metadata["mermaidjsDiagram"] = generated_mermaidjs_diagram updated_conversation = message_to_log( user_message=q, @@ -441,7 +441,7 @@ def generate_chatml_messages_with_context( "query": chat.get("intent", {}).get("inferred-queries", [user_message])[0], } - if not is_none_or_empty(chat.get("excalidrawDiagram")) and role == "assistant": + if not is_none_or_empty(chat.get("mermaidjsDiagram")) and role == "assistant": generated_assets["diagram"] = { "query": chat.get("intent", {}).get("inferred-queries", [user_message])[0], } @@ -593,6 +593,11 @@ def clean_json(response: str): return response.strip().replace("\n", "").removeprefix("```json").removesuffix("```") +def clean_mermaidjs(response: str): + """Remove any markdown mermaidjs codeblock and newline formatting if present. Useful for non schema enforceable models""" + return response.strip().removeprefix("```mermaid").removesuffix("```") + + def clean_code_python(code: str): """Remove any markdown codeblock and newline formatting if present. Useful for non schema enforceable models""" return code.strip().removeprefix("```python").removesuffix("```") diff --git a/src/khoj/processor/embeddings.py b/src/khoj/processor/embeddings.py index b224e7f5..0e7b6657 100644 --- a/src/khoj/processor/embeddings.py +++ b/src/khoj/processor/embeddings.py @@ -1,6 +1,8 @@ import logging from typing import List +from urllib.parse import urlparse +import openai import requests import tqdm from sentence_transformers import CrossEncoder, SentenceTransformer @@ -13,7 +15,14 @@ from tenacity import ( ) from torch import nn -from khoj.utils.helpers import fix_json_dict, get_device, merge_dicts, timer +from khoj.database.models import SearchModelConfig +from khoj.utils.helpers import ( + fix_json_dict, + get_device, + get_openai_client, + merge_dicts, + timer, +) from khoj.utils.rawconfig import SearchResponse logger = logging.getLogger(__name__) @@ -25,6 +34,7 @@ class EmbeddingsModel: model_name: str = "thenlper/gte-small", embeddings_inference_endpoint: str = None, embeddings_inference_endpoint_api_key: str = None, + embeddings_inference_endpoint_type=SearchModelConfig.ApiType.LOCAL, query_encode_kwargs: dict = {}, docs_encode_kwargs: dict = {}, model_kwargs: dict = {}, @@ -37,15 +47,16 @@ class EmbeddingsModel: self.model_name = model_name self.inference_endpoint = embeddings_inference_endpoint self.api_key = embeddings_inference_endpoint_api_key - with timer(f"Loaded embedding model {self.model_name}", logger): - self.embeddings_model = SentenceTransformer(self.model_name, **self.model_kwargs) - - def inference_server_enabled(self) -> bool: - return self.api_key is not None and self.inference_endpoint is not None + self.inference_endpoint_type = embeddings_inference_endpoint_type + if self.inference_endpoint_type == SearchModelConfig.ApiType.LOCAL: + with timer(f"Loaded embedding model {self.model_name}", logger): + self.embeddings_model = SentenceTransformer(self.model_name, **self.model_kwargs) def embed_query(self, query): - if self.inference_server_enabled(): - return self.embed_with_api([query])[0] + if self.inference_endpoint_type == SearchModelConfig.ApiType.HUGGINGFACE: + return self.embed_with_hf([query])[0] + elif self.inference_endpoint_type == SearchModelConfig.ApiType.OPENAI: + return self.embed_with_openai([query])[0] return self.embeddings_model.encode([query], **self.query_encode_kwargs)[0] @retry( @@ -54,7 +65,7 @@ class EmbeddingsModel: stop=stop_after_attempt(5), before_sleep=before_sleep_log(logger, logging.DEBUG), ) - def embed_with_api(self, docs): + def embed_with_hf(self, docs): payload = {"inputs": docs} headers = { "Authorization": f"Bearer {self.api_key}", @@ -71,23 +82,38 @@ class EmbeddingsModel: raise e return response.json()["embeddings"] + @retry( + retry=retry_if_exception_type(requests.exceptions.HTTPError), + wait=wait_random_exponential(multiplier=1, max=10), + stop=stop_after_attempt(5), + before_sleep=before_sleep_log(logger, logging.DEBUG), + ) + def embed_with_openai(self, docs): + client = get_openai_client(self.api_key, self.inference_endpoint) + response = client.embeddings.create(input=docs, model=self.model_name, encoding_format="float") + return [item.embedding for item in response.data] + def embed_documents(self, docs): - if self.inference_server_enabled(): - if "huggingface" not in self.inference_endpoint: - logger.warning( - f"Unsupported inference endpoint: {self.inference_endpoint}. Only HuggingFace supported. Generating embeddings on device instead." - ) - return self.embeddings_model.encode(docs, **self.docs_encode_kwargs).tolist() - # break up the docs payload in chunks of 1000 to avoid hitting rate limits - embeddings = [] - with tqdm.tqdm(total=len(docs)) as pbar: - for i in range(0, len(docs), 1000): - docs_to_embed = docs[i : i + 1000] - generated_embeddings = self.embed_with_api(docs_to_embed) - embeddings += generated_embeddings - pbar.update(1000) - return embeddings - return self.embeddings_model.encode(docs, **self.docs_encode_kwargs).tolist() if docs else [] + if self.inference_endpoint_type == SearchModelConfig.ApiType.LOCAL: + return self.embeddings_model.encode(docs, **self.docs_encode_kwargs).tolist() if docs else [] + elif self.inference_endpoint_type == SearchModelConfig.ApiType.HUGGINGFACE: + embed_with_api = self.embed_with_hf + elif self.inference_endpoint_type == SearchModelConfig.ApiType.OPENAI: + embed_with_api = self.embed_with_openai + else: + logger.warning( + f"Unsupported inference endpoint: {self.inference_endpoint_type}. Generating embeddings locally instead." + ) + return self.embeddings_model.encode(docs, **self.docs_encode_kwargs).tolist() + # break up the docs payload in chunks of 1000 to avoid hitting rate limits + embeddings = [] + with tqdm.tqdm(total=len(docs)) as pbar: + for i in range(0, len(docs), 1000): + docs_to_embed = docs[i : i + 1000] + generated_embeddings = embed_with_api(docs_to_embed) + embeddings += generated_embeddings + pbar.update(1000) + return embeddings class CrossEncoderModel: diff --git a/src/khoj/processor/image/generate.py b/src/khoj/processor/image/generate.py index a4628115..252e61eb 100644 --- a/src/khoj/processor/image/generate.py +++ b/src/khoj/processor/image/generate.py @@ -111,7 +111,7 @@ async def text_to_image( image_url = upload_image(webp_image_bytes, user.uuid) if not image_url: - image = base64.b64encode(webp_image_bytes).decode("utf-8") + image = f"data:image/webp;base64,{base64.b64encode(webp_image_bytes).decode('utf-8')}" yield image_url or image, status_code, image_prompt @@ -119,25 +119,27 @@ async def text_to_image( def generate_image_with_openai( improved_image_prompt: str, text_to_image_config: TextToImageModelConfig, text2image_model: str ): - "Generate image using OpenAI API" + "Generate image using OpenAI (compatible) API" - # Get the API key from the user's configuration + # Get the API config from the user's configuration + api_key = None if text_to_image_config.api_key: api_key = text_to_image_config.api_key + openai_client = openai.OpenAI(api_key=api_key) elif text_to_image_config.ai_model_api: api_key = text_to_image_config.ai_model_api.api_key + api_base_url = text_to_image_config.ai_model_api.api_base_url + openai_client = openai.OpenAI(api_key=api_key, base_url=api_base_url) elif state.openai_client: - api_key = state.openai_client.api_key - auth_header = {"Authorization": f"Bearer {api_key}"} if api_key else {} + openai_client = state.openai_client # Generate image using OpenAI API OPENAI_IMAGE_GEN_STYLE = "vivid" - response = state.openai_client.images.generate( + response = openai_client.images.generate( prompt=improved_image_prompt, model=text2image_model, style=OPENAI_IMAGE_GEN_STYLE, response_format="b64_json", - extra_headers=auth_header, ) # Extract the base64 image from the response diff --git a/src/khoj/processor/tools/online_search.py b/src/khoj/processor/tools/online_search.py index 5e73fb07..33cc3056 100644 --- a/src/khoj/processor/tools/online_search.py +++ b/src/khoj/processor/tools/online_search.py @@ -30,6 +30,8 @@ from khoj.utils.rawconfig import LocationData logger = logging.getLogger(__name__) +GOOGLE_SEARCH_API_KEY = os.getenv("GOOGLE_SEARCH_API_KEY") +GOOGLE_SEARCH_ENGINE_ID = os.getenv("GOOGLE_SEARCH_ENGINE_ID") SERPER_DEV_API_KEY = os.getenv("SERPER_DEV_API_KEY") SERPER_DEV_URL = "https://google.serper.dev/search" @@ -96,19 +98,25 @@ async def search_online( yield response_dict return - logger.info(f"๐ŸŒ Searching the Internet for {subqueries}") + if GOOGLE_SEARCH_API_KEY and GOOGLE_SEARCH_ENGINE_ID: + search_engine = "Google" + search_func = search_with_google + elif SERPER_DEV_API_KEY: + search_engine = "Serper" + search_func = search_with_serper + elif JINA_API_KEY: + search_engine = "Jina" + search_func = search_with_jina + else: + search_engine = "Searxng" + search_func = search_with_searxng + + logger.info(f"๐ŸŒ Searching the Internet with {search_engine} for {subqueries}") if send_status_func: subqueries_str = "\n- " + "\n- ".join(subqueries) async for event in send_status_func(f"**Searching the Internet for**: {subqueries_str}"): yield {ChatEvent.STATUS: event} - if SERPER_DEV_API_KEY: - search_func = search_with_serper - elif JINA_API_KEY: - search_func = search_with_jina - else: - search_func = search_with_searxng - with timer(f"Internet searches for {subqueries} took", logger): search_tasks = [search_func(subquery, location) for subquery in subqueries] search_results = await asyncio.gather(*search_tasks) @@ -195,6 +203,56 @@ async def search_with_searxng(query: str, location: LocationData) -> Tuple[str, return query, {} +async def search_with_google(query: str, location: LocationData) -> Tuple[str, Dict[str, List[Dict]]]: + country_code = location.country_code.lower() if location and location.country_code else "us" + base_url = "https://www.googleapis.com/customsearch/v1" + params = { + "key": GOOGLE_SEARCH_API_KEY, + "cx": GOOGLE_SEARCH_ENGINE_ID, + "q": query, + "cr": f"country{country_code.upper()}", # Country restrict parameter + "gl": country_code, # Geolocation parameter + } + + async with aiohttp.ClientSession() as session: + async with session.get(base_url, params=params) as response: + if response.status != 200: + logger.error(await response.text()) + return query, {} + + json_response = await response.json() + + # Transform Google's response format to match Serper's format + organic_results = [] + if "items" in json_response: + organic_results = [ + { + "title": item.get("title", ""), + "link": item.get("link", ""), + "snippet": item.get("snippet", ""), + "content": None, # Google Search API doesn't provide full content + } + for item in json_response["items"] + ] + + # Format knowledge graph if available + knowledge_graph = {} + if "knowledge_graph" in json_response: + kg = json_response["knowledge_graph"] + knowledge_graph = { + "title": kg.get("name", ""), + "description": kg.get("description", ""), + "type": kg.get("type", ""), + } + + extracted_search_result: Dict[str, Any] = {"organic": organic_results} + + if knowledge_graph: + extracted_search_result["knowledgeGraph"] = knowledge_graph + + return query, extracted_search_result + + async def search_with_serper(query: str, location: LocationData) -> Tuple[str, Dict[str, List[Dict]]]: country_code = location.country_code.lower() if location and location.country_code else "us" payload = json.dumps({"q": query, "gl": country_code}) diff --git a/src/khoj/routers/api.py b/src/khoj/routers/api.py index a29e993a..44375bca 100644 --- a/src/khoj/routers/api.py +++ b/src/khoj/routers/api.py @@ -9,6 +9,7 @@ import uuid from typing import Any, Callable, List, Optional, Set, Union import cron_descriptor +import openai import pytz from apscheduler.job import Job from apscheduler.triggers.cron import CronTrigger @@ -264,12 +265,21 @@ async def transcribe( if not speech_to_text_config: # If the user has not configured a speech to text model, return an unsupported on server error status_code = 501 - elif state.openai_client and speech_to_text_config.model_type == SpeechToTextModelOptions.ModelType.OPENAI: - speech2text_model = speech_to_text_config.model_name - user_message = await transcribe_audio(audio_file, speech2text_model, client=state.openai_client) elif speech_to_text_config.model_type == SpeechToTextModelOptions.ModelType.OFFLINE: speech2text_model = speech_to_text_config.model_name user_message = await transcribe_audio_offline(audio_filename, speech2text_model) + elif speech_to_text_config.model_type == SpeechToTextModelOptions.ModelType.OPENAI: + speech2text_model = speech_to_text_config.model_name + if speech_to_text_config.ai_model_api: + api_key = speech_to_text_config.ai_model_api.api_key + api_base_url = speech_to_text_config.ai_model_api.api_base_url + openai_client = openai.OpenAI(api_key=api_key, base_url=api_base_url) + elif state.openai_client: + openai_client = state.openai_client + if openai_client: + user_message = await transcribe_audio(audio_file, speech2text_model, client=openai_client) + else: + status_code = 501 finally: # Close and Delete the temporary audio file audio_file.close() @@ -392,7 +402,8 @@ async def extract_references_and_questions( filters_in_query += " ".join([f'file:"{filter}"' for filter in conversation.file_filters]) using_offline_chat = False - logger.debug(f"Filters in query: {filters_in_query}") + if is_none_or_empty(filters_in_query): + logger.debug(f"Filters in query: {filters_in_query}") personality_context = prompts.personality_context.format(personality=agent.personality) if agent else "" diff --git a/src/khoj/routers/api_chat.py b/src/khoj/routers/api_chat.py index 1f32ffda..d3b933ee 100644 --- a/src/khoj/routers/api_chat.py +++ b/src/khoj/routers/api_chat.py @@ -51,7 +51,7 @@ from khoj.routers.helpers import ( construct_automation_created_message, create_automation, gather_raw_query_files, - generate_excalidraw_diagram, + generate_mermaidjs_diagram, generate_summary_from_files, get_conversation_command, is_query_empty, @@ -781,20 +781,25 @@ async def chat( generated_images: List[str] = [] generated_files: List[FileAttachment] = [] - generated_excalidraw_diagram: str = None + generated_mermaidjs_diagram: str = None program_execution_context: List[str] = [] if conversation_commands == [ConversationCommand.Default]: - chosen_io = await aget_data_sources_and_output_format( - q, - meta_log, - is_automated_task, - user=user, - query_images=uploaded_images, - agent=agent, - query_files=attached_file_context, - tracer=tracer, - ) + try: + chosen_io = await aget_data_sources_and_output_format( + q, + meta_log, + is_automated_task, + user=user, + query_images=uploaded_images, + agent=agent, + query_files=attached_file_context, + tracer=tracer, + ) + except ValueError as e: + logger.error(f"Error getting data sources and output format: {e}. Falling back to default.") + conversation_commands = [ConversationCommand.General] + conversation_commands = chosen_io.get("sources") + [chosen_io.get("output")] # If we're doing research, we don't want to do anything else @@ -1156,7 +1161,7 @@ async def chat( inferred_queries = [] diagram_description = "" - async for result in generate_excalidraw_diagram( + async for result in generate_mermaidjs_diagram( q=defiltered_query, conversation_history=meta_log, location_data=location, @@ -1172,12 +1177,12 @@ async def chat( if isinstance(result, dict) and ChatEvent.STATUS in result: yield result[ChatEvent.STATUS] else: - better_diagram_description_prompt, excalidraw_diagram_description = result - if better_diagram_description_prompt and excalidraw_diagram_description: + better_diagram_description_prompt, mermaidjs_diagram_description = result + if better_diagram_description_prompt and mermaidjs_diagram_description: inferred_queries.append(better_diagram_description_prompt) - diagram_description = excalidraw_diagram_description + diagram_description = mermaidjs_diagram_description - generated_excalidraw_diagram = diagram_description + generated_mermaidjs_diagram = diagram_description generated_asset_results["diagrams"] = { "query": better_diagram_description_prompt, @@ -1186,7 +1191,7 @@ async def chat( async for result in send_event( ChatEvent.GENERATED_ASSETS, { - "excalidrawDiagram": excalidraw_diagram_description, + "mermaidjsDiagram": mermaidjs_diagram_description, }, ): yield result @@ -1226,7 +1231,7 @@ async def chat( raw_query_files, generated_images, generated_files, - generated_excalidraw_diagram, + generated_mermaidjs_diagram, program_execution_context, generated_asset_results, tracer, diff --git a/src/khoj/routers/email.py b/src/khoj/routers/email.py index 701db0a6..ce9e0ae6 100644 --- a/src/khoj/routers/email.py +++ b/src/khoj/routers/email.py @@ -1,5 +1,6 @@ import logging import os +from urllib.parse import quote import markdown_it import resend @@ -29,7 +30,7 @@ def is_resend_enabled(): async def send_magic_link_email(email, unique_id, host): - sign_in_link = f"{host}auth/magic?code={unique_id}&email={email}" + sign_in_link = f"{host}auth/magic?code={quote(unique_id)}&email={quote(email)}" if not is_resend_enabled(): logger.debug(f"Email sending disabled. Share this sign-in link with the user: {sign_in_link}") diff --git a/src/khoj/routers/helpers.py b/src/khoj/routers/helpers.py index dfe53f9a..67b367b0 100644 --- a/src/khoj/routers/helpers.py +++ b/src/khoj/routers/helpers.py @@ -97,6 +97,7 @@ from khoj.processor.conversation.utils import ( ChatEvent, ThreadedGenerator, clean_json, + clean_mermaidjs, construct_chat_history, generate_chatml_messages_with_context, save_to_conversation_log, @@ -823,7 +824,7 @@ async def generate_better_diagram_description( elif online_results[result].get("webpages"): simplified_online_results[result] = online_results[result]["webpages"] - improve_diagram_description_prompt = prompts.improve_diagram_description_prompt.format( + improve_diagram_description_prompt = prompts.improve_excalidraw_diagram_description_prompt.format( query=q, chat_history=chat_history, location=location, @@ -887,6 +888,133 @@ async def generate_excalidraw_diagram_from_description( return response +async def generate_mermaidjs_diagram( + q: str, + conversation_history: Dict[str, Any], + location_data: LocationData, + note_references: List[Dict[str, Any]], + online_results: Optional[dict] = None, + query_images: List[str] = None, + user: KhojUser = None, + agent: Agent = None, + send_status_func: Optional[Callable] = None, + query_files: str = None, + tracer: dict = {}, +): + if send_status_func: + async for event in send_status_func("**Enhancing the Diagramming Prompt**"): + yield {ChatEvent.STATUS: event} + + better_diagram_description_prompt = await generate_better_mermaidjs_diagram_description( + q=q, + conversation_history=conversation_history, + location_data=location_data, + note_references=note_references, + online_results=online_results, + query_images=query_images, + user=user, + agent=agent, + query_files=query_files, + tracer=tracer, + ) + + if send_status_func: + async for event in send_status_func(f"**Diagram to Create:**:\n{better_diagram_description_prompt}"): + yield {ChatEvent.STATUS: event} + + mermaidjs_diagram_description = await generate_mermaidjs_diagram_from_description( + q=better_diagram_description_prompt, + user=user, + agent=agent, + tracer=tracer, + ) + + inferred_queries = f"Instruction: {better_diagram_description_prompt}" + + yield inferred_queries, mermaidjs_diagram_description + + +async def generate_better_mermaidjs_diagram_description( + q: str, + conversation_history: Dict[str, Any], + location_data: LocationData, + note_references: List[Dict[str, Any]], + online_results: Optional[dict] = None, + query_images: List[str] = None, + user: KhojUser = None, + agent: Agent = None, + query_files: str = None, + tracer: dict = {}, +) -> str: + """ + Generate a diagram description from the given query and context + """ + + today_date = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d, %A") + personality_context = ( + prompts.personality_context.format(personality=agent.personality) if agent and agent.personality else "" + ) + + location = f"{location_data}" if location_data else "Unknown" + + user_references = "\n\n".join([f"# {item['compiled']}" for item in note_references]) + + chat_history = construct_chat_history(conversation_history) + + simplified_online_results = {} + + if online_results: + for result in online_results: + if online_results[result].get("answerBox"): + simplified_online_results[result] = online_results[result]["answerBox"] + elif online_results[result].get("webpages"): + simplified_online_results[result] = online_results[result]["webpages"] + + improve_diagram_description_prompt = prompts.improve_mermaid_js_diagram_description_prompt.format( + query=q, + chat_history=chat_history, + location=location, + current_date=today_date, + references=user_references, + online_results=simplified_online_results, + personality_context=personality_context, + ) + + with timer("Chat actor: Generate better Mermaid.js diagram description", logger): + response = await send_message_to_model_wrapper( + improve_diagram_description_prompt, + query_images=query_images, + user=user, + query_files=query_files, + tracer=tracer, + ) + response = response.strip() + if response.startswith(('"', "'")) and response.endswith(('"', "'")): + response = response[1:-1] + + return response + + +async def generate_mermaidjs_diagram_from_description( + q: str, + user: KhojUser = None, + agent: Agent = None, + tracer: dict = {}, +) -> str: + personality_context = ( + prompts.personality_context.format(personality=agent.personality) if agent and agent.personality else "" + ) + + mermaidjs_diagram_generation = prompts.mermaid_js_diagram_generation_prompt.format( + personality_context=personality_context, + query=q, + ) + + with timer("Chat actor: Generate Mermaid.js diagram", logger): + raw_response = await send_message_to_model_wrapper(query=mermaidjs_diagram_generation, user=user, tracer=tracer) + return clean_mermaidjs(raw_response.strip()) + + async def generate_better_image_prompt( q: str, conversation_history: str, @@ -1224,7 +1352,7 @@ def generate_chat_response( raw_query_files: List[FileAttachment] = None, generated_images: List[str] = None, raw_generated_files: List[FileAttachment] = [], - generated_excalidraw_diagram: str = None, + generated_mermaidjs_diagram: str = None, program_execution_context: List[str] = [], generated_asset_results: Dict[str, Dict] = {}, tracer: dict = {}, @@ -1252,7 +1380,7 @@ def generate_chat_response( raw_query_files=raw_query_files, generated_images=generated_images, raw_generated_files=raw_generated_files, - generated_excalidraw_diagram=generated_excalidraw_diagram, + generated_mermaidjs_diagram=generated_mermaidjs_diagram, tracer=tracer, ) @@ -1785,7 +1913,7 @@ def scheduled_chat( raw_response = requests.post(url, headers=headers, json=json_payload, allow_redirects=False) # Handle redirect manually if necessary - if raw_response.status_code in [301, 302]: + if raw_response.status_code in [301, 302, 308]: redirect_url = raw_response.headers["Location"] logger.info(f"Redirecting to {redirect_url}") raw_response = requests.post(redirect_url, headers=headers, json=json_payload) @@ -1967,7 +2095,7 @@ class MessageProcessor: self.raw_response = "" self.generated_images = [] self.generated_files = [] - self.generated_excalidraw_diagram = [] + self.generated_mermaidjs_diagram = [] def convert_message_chunk_to_json(self, raw_chunk: str) -> Dict[str, Any]: if raw_chunk.startswith("{") and raw_chunk.endswith("}"): @@ -2014,8 +2142,8 @@ class MessageProcessor: self.generated_images = chunk_data[key] elif key == "files": self.generated_files = chunk_data[key] - elif key == "excalidrawDiagram": - self.generated_excalidraw_diagram = chunk_data[key] + elif key == "mermaidjsDiagram": + self.generated_mermaidjs_diagram = chunk_data[key] def handle_json_response(self, json_data: Dict[str, str]) -> str | Dict[str, str]: if "image" in json_data or "details" in json_data: @@ -2052,7 +2180,7 @@ async def read_chat_stream(response_iterator: AsyncGenerator[str, None]) -> Dict "usage": processor.usage, "images": processor.generated_images, "files": processor.generated_files, - "excalidrawDiagram": processor.generated_excalidraw_diagram, + "mermaidjsDiagram": processor.generated_mermaidjs_diagram, } diff --git a/src/khoj/utils/constants.py b/src/khoj/utils/constants.py index 59534895..6e89594d 100644 --- a/src/khoj/utils/constants.py +++ b/src/khoj/utils/constants.py @@ -15,7 +15,7 @@ default_offline_chat_models = [ "bartowski/Llama-3.2-3B-Instruct-GGUF", "bartowski/gemma-2-9b-it-GGUF", "bartowski/gemma-2-2b-it-GGUF", - "Qwen/Qwen2.5-14B-Instruct-GGUF", + "bartowski/Qwen2.5-14B-Instruct-GGUF", ] default_openai_chat_models = ["gpt-4o-mini", "gpt-4o"] default_gemini_chat_models = ["gemini-1.5-flash", "gemini-1.5-pro"] diff --git a/src/khoj/utils/helpers.py b/src/khoj/utils/helpers.py index 4e16d6b5..e3cab3c7 100644 --- a/src/khoj/utils/helpers.py +++ b/src/khoj/utils/helpers.py @@ -355,7 +355,7 @@ command_descriptions = { command_descriptions_for_agent = { ConversationCommand.General: "Agent can use the agents knowledge base and general knowledge.", - ConversationCommand.Notes: "Agent can search the users knowledge base for information.", + ConversationCommand.Notes: "Agent can search the personal knowledge base for information, as well as its own.", ConversationCommand.Online: "Agent can search the internet for information.", ConversationCommand.Webpage: "Agent can read suggested web pages for information.", ConversationCommand.Summarize: "Agent can read an entire document. Agents knowledge base must be a single document.", diff --git a/src/khoj/utils/initialization.py b/src/khoj/utils/initialization.py index 83062a21..6c0d6d42 100644 --- a/src/khoj/utils/initialization.py +++ b/src/khoj/utils/initialization.py @@ -43,14 +43,14 @@ def initialization(interactive: bool = True): "๐Ÿ—ฃ๏ธ Configure chat models available to your server. You can always update these at /server/admin using your admin account" ) - openai_api_base = os.getenv("OPENAI_API_BASE") - provider = "Ollama" if openai_api_base and openai_api_base.endswith(":11434/v1/") else "OpenAI" - openai_api_key = os.getenv("OPENAI_API_KEY", "placeholder" if openai_api_base else None) + openai_base_url = os.getenv("OPENAI_BASE_URL") + provider = "Ollama" if openai_base_url and openai_base_url.endswith(":11434/v1/") else "OpenAI" + openai_api_key = os.getenv("OPENAI_API_KEY", "placeholder" if openai_base_url else None) default_chat_models = default_openai_chat_models - if openai_api_base: + if openai_base_url: # Get available chat models from OpenAI compatible API try: - openai_client = openai.OpenAI(api_key=openai_api_key, base_url=openai_api_base) + openai_client = openai.OpenAI(api_key=openai_api_key, base_url=openai_base_url) default_chat_models = [model.id for model in openai_client.models.list()] # Put the available default OpenAI models at the top valid_default_models = [model for model in default_openai_chat_models if model in default_chat_models] @@ -66,7 +66,7 @@ def initialization(interactive: bool = True): ChatModel.ModelType.OPENAI, default_chat_models, default_api_key=openai_api_key, - api_base_url=openai_api_base, + api_base_url=openai_base_url, vision_enabled=True, is_offline=False, interactive=interactive, diff --git a/versions.json b/versions.json index e7dced26..47ff6efa 100644 --- a/versions.json +++ b/versions.json @@ -108,5 +108,6 @@ "1.32.2": "0.15.0", "1.33.0": "0.15.0", "1.33.1": "0.15.0", - "1.33.2": "0.15.0" + "1.33.2": "0.15.0", + "1.34.0": "0.15.0" }