From 6bab8b5bd40f3aa9a276e7005b638a25023009bc Mon Sep 17 00:00:00 2001 From: timothycarambat Date: Thu, 25 Jul 2024 14:10:17 -0700 Subject: [PATCH 01/18] ui adjustments for order flow back nav on order flow fix bad schema ref --- .../pages/FineTuning/Steps/OrderDetails/index.jsx | 2 +- frontend/src/pages/FineTuning/index.jsx | 15 ++++++++++++--- server/models/fineTuning.js | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/frontend/src/pages/FineTuning/Steps/OrderDetails/index.jsx b/frontend/src/pages/FineTuning/Steps/OrderDetails/index.jsx index 6e71db80d..b0f44a462 100644 --- a/frontend/src/pages/FineTuning/Steps/OrderDetails/index.jsx +++ b/frontend/src/pages/FineTuning/Steps/OrderDetails/index.jsx @@ -8,7 +8,7 @@ export default function OrderDetails({ setSettings, setStep }) { useEffect(() => { FineTuning.info() .then((res) => { - setInfo(res); + setInfo(res ?? {}); setSettings((prev) => { return { ...prev, tuningInfo: res }; }); diff --git a/frontend/src/pages/FineTuning/index.jsx b/frontend/src/pages/FineTuning/index.jsx index f1c293306..4406d8310 100644 --- a/frontend/src/pages/FineTuning/index.jsx +++ b/frontend/src/pages/FineTuning/index.jsx @@ -3,7 +3,7 @@ import FineTuningSteps, { FineTuningCreationLayout } from "./Steps"; import { CheckCircle, Circle, Sparkle } from "@phosphor-icons/react"; import { isMobile } from "react-device-detect"; -function SideBarSelection({ currentStep }) { +function SideBarSelection({ setStep, currentStep }) { const currentIndex = Object.keys(FineTuningSteps).indexOf(currentStep); return (
-
{props.name}
+ {isDone ? ( + + ) : ( +
{props.name}
+ )}
{isDone ? ( @@ -60,7 +69,7 @@ export default function FineTuningFlow() {

Custom Fine-Tuned Model

- +
{StepPage.component({ settings, setSettings, setStep })} diff --git a/server/models/fineTuning.js b/server/models/fineTuning.js index 629cfc015..8ca5b84ec 100644 --- a/server/models/fineTuning.js +++ b/server/models/fineTuning.js @@ -72,7 +72,7 @@ const FineTuning = { workspaceId: { in: workspaceIds, }, - ...(feedback === true ? { feedback: 1 } : {}), + ...(feedback === true ? { feedbackScore: true } : {}), }); return count; }, @@ -141,7 +141,7 @@ const FineTuning = { workspaceId: { in: workspaces.map((ws) => ws.id), }, - ...(feedback === true ? { feedback: 1 } : {}), + ...(feedback === true ? { feedbackScore: true } : {}), }); const preparedData = chats.map((chat) => { const responseJson = safeJsonParse(chat.response); From 7a2ffefdc37fe88d5c7e5264d6989dc57a7e161a Mon Sep 17 00:00:00 2001 From: timothycarambat Date: Thu, 25 Jul 2024 17:39:29 -0700 Subject: [PATCH 02/18] update case stmt for duplicate groq model --- .vscode/settings.json | 1 + server/utils/AiProviders/groq/index.js | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5e26e4778..6b47d3871 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -29,6 +29,7 @@ "mbox", "Milvus", "Mintplex", + "mixtral", "moderations", "numpages", "Ollama", diff --git a/server/utils/AiProviders/groq/index.js b/server/utils/AiProviders/groq/index.js index ccfc647a0..6b750c2ad 100644 --- a/server/utils/AiProviders/groq/index.js +++ b/server/utils/AiProviders/groq/index.js @@ -48,7 +48,6 @@ class GroqLLM { case "llama3-8b-8192": return 8192; case "llama-3.1-70b-versatile": - case "llama-3.1-8b-instant": case "llama-3.1-8b-instant": return 131072; case "mixtral-8x7b-32768": From ed49032db4dcb30efd6b640794373716394dfb26 Mon Sep 17 00:00:00 2001 From: timothycarambat Date: Fri, 26 Jul 2024 10:34:53 -0700 Subject: [PATCH 03/18] Revert "update chown in DO droplet (#1966)" This reverts commit 3457cc4b7a19f003b4fa3f7654b19f449249d5f9. --- .../aws/cloudformation/cloudformation_create_anythingllm.json | 2 +- cloud-deployments/digitalocean/terraform/user_data.tp1 | 3 +-- cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json b/cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json index a500e54cd..e81e16b61 100644 --- a/cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json +++ b/cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json @@ -90,7 +90,7 @@ "touch /home/ec2-user/anythingllm/.env\n", "sudo chown ec2-user:ec2-user -R /home/ec2-user/anythingllm\n", "docker pull mintplexlabs/anythingllm:master\n", - "docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/ec2-user/anythingllm:/app/server/storage -v /home/ec2-user/anythingllm/.env:/app/server/.env -e STORAGE_DIR=\"/app/server/storage\" mintplexlabs/anythingllm\n", + "docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/ec2-user/anythingllm:/app/server/storage -v /home/ec2-user/anythingllm/.env:/app/server/.env -e STORAGE_DIR=\"/app/server/storage\" mintplexlabs/anythingllm:master\n", "echo \"Container ID: $(sudo docker ps --latest --quiet)\"\n", "export ONLINE=$(curl -Is http://localhost:3001/api/ping | head -n 1|cut -d$' ' -f2)\n", "echo \"Health check: $ONLINE\"\n", diff --git a/cloud-deployments/digitalocean/terraform/user_data.tp1 b/cloud-deployments/digitalocean/terraform/user_data.tp1 index d23d566eb..33455a4e8 100644 --- a/cloud-deployments/digitalocean/terraform/user_data.tp1 +++ b/cloud-deployments/digitalocean/terraform/user_data.tp1 @@ -10,10 +10,9 @@ sudo systemctl start docker mkdir -p /home/anythingllm touch /home/anythingllm/.env -sudo chown -R ubuntu:ubuntu /home/anythingllm sudo docker pull mintplexlabs/anythingllm:master -sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm +sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm:master echo "Container ID: $(sudo docker ps --latest --quiet)" export ONLINE=$(curl -Is http://localhost:3001/api/ping | head -n 1|cut -d$' ' -f2) diff --git a/cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml b/cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml index 5a4381022..72a5a0964 100644 --- a/cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml +++ b/cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml @@ -35,7 +35,7 @@ resources: sudo chown -R ubuntu:ubuntu /home/anythingllm sudo docker pull mintplexlabs/anythingllm:master - sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm + sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm:master echo "Container ID: $(sudo docker ps --latest --quiet)" export ONLINE=$(curl -Is http://localhost:3001/api/ping | head -n 1|cut -d$' ' -f2) From 0cba89a54bb78ec074ea8a8faf70fd354406e3e6 Mon Sep 17 00:00:00 2001 From: timothycarambat Date: Fri, 26 Jul 2024 10:36:05 -0700 Subject: [PATCH 04/18] remove master tag on cloud-deployment templates --- .../aws/cloudformation/cloudformation_create_anythingllm.json | 4 ++-- cloud-deployments/digitalocean/terraform/user_data.tp1 | 4 ++-- cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json b/cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json index e81e16b61..b10bbc2db 100644 --- a/cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json +++ b/cloud-deployments/aws/cloudformation/cloudformation_create_anythingllm.json @@ -89,8 +89,8 @@ "mkdir -p /home/ec2-user/anythingllm\n", "touch /home/ec2-user/anythingllm/.env\n", "sudo chown ec2-user:ec2-user -R /home/ec2-user/anythingllm\n", - "docker pull mintplexlabs/anythingllm:master\n", - "docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/ec2-user/anythingllm:/app/server/storage -v /home/ec2-user/anythingllm/.env:/app/server/.env -e STORAGE_DIR=\"/app/server/storage\" mintplexlabs/anythingllm:master\n", + "docker pull mintplexlabs/anythingllm\n", + "docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/ec2-user/anythingllm:/app/server/storage -v /home/ec2-user/anythingllm/.env:/app/server/.env -e STORAGE_DIR=\"/app/server/storage\" mintplexlabs/anythingllm\n", "echo \"Container ID: $(sudo docker ps --latest --quiet)\"\n", "export ONLINE=$(curl -Is http://localhost:3001/api/ping | head -n 1|cut -d$' ' -f2)\n", "echo \"Health check: $ONLINE\"\n", diff --git a/cloud-deployments/digitalocean/terraform/user_data.tp1 b/cloud-deployments/digitalocean/terraform/user_data.tp1 index 33455a4e8..cd239c6b4 100644 --- a/cloud-deployments/digitalocean/terraform/user_data.tp1 +++ b/cloud-deployments/digitalocean/terraform/user_data.tp1 @@ -11,8 +11,8 @@ sudo systemctl start docker mkdir -p /home/anythingllm touch /home/anythingllm/.env -sudo docker pull mintplexlabs/anythingllm:master -sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm:master +sudo docker pull mintplexlabs/anythingllm +sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm echo "Container ID: $(sudo docker ps --latest --quiet)" export ONLINE=$(curl -Is http://localhost:3001/api/ping | head -n 1|cut -d$' ' -f2) diff --git a/cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml b/cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml index 72a5a0964..3f44d5af8 100644 --- a/cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml +++ b/cloud-deployments/gcp/deployment/gcp_deploy_anything_llm.yaml @@ -34,8 +34,8 @@ resources: touch /home/anythingllm/.env sudo chown -R ubuntu:ubuntu /home/anythingllm - sudo docker pull mintplexlabs/anythingllm:master - sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm:master + sudo docker pull mintplexlabs/anythingllm + sudo docker run -d -p 3001:3001 --cap-add SYS_ADMIN -v /home/anythingllm:/app/server/storage -v /home/anythingllm/.env:/app/server/.env -e STORAGE_DIR="/app/server/storage" mintplexlabs/anythingllm echo "Container ID: $(sudo docker ps --latest --quiet)" export ONLINE=$(curl -Is http://localhost:3001/api/ping | head -n 1|cut -d$' ' -f2) From 013c0b9575ae6a87af87275e326041c4e0afeeee Mon Sep 17 00:00:00 2001 From: timothycarambat Date: Fri, 26 Jul 2024 10:53:05 -0700 Subject: [PATCH 05/18] remove LMStudio restriction for model selector --- frontend/src/hooks/useGetProvidersModels.js | 1 - .../ChatSettings/WorkspaceLLMSelection/index.jsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/hooks/useGetProvidersModels.js b/frontend/src/hooks/useGetProvidersModels.js index 064ad17c8..c56f42fdc 100644 --- a/frontend/src/hooks/useGetProvidersModels.js +++ b/frontend/src/hooks/useGetProvidersModels.js @@ -4,7 +4,6 @@ import { useEffect, useState } from "react"; // Providers which cannot use this feature for workspace<>model selection export const DISABLED_PROVIDERS = [ "azure", - "lmstudio", "native", "textgenwebui", "generic-openai", diff --git a/frontend/src/pages/WorkspaceSettings/ChatSettings/WorkspaceLLMSelection/index.jsx b/frontend/src/pages/WorkspaceSettings/ChatSettings/WorkspaceLLMSelection/index.jsx index c1841929c..e065aff4a 100644 --- a/frontend/src/pages/WorkspaceSettings/ChatSettings/WorkspaceLLMSelection/index.jsx +++ b/frontend/src/pages/WorkspaceSettings/ChatSettings/WorkspaceLLMSelection/index.jsx @@ -16,7 +16,7 @@ const NO_MODEL_SELECTION = [ "generic-openai", "bedrock", ]; -const DISABLED_PROVIDERS = ["azure", "lmstudio", "native"]; +const DISABLED_PROVIDERS = ["azure", "native"]; const LLM_DEFAULT = { name: "System default", value: "default", From ae58a2cb0db7c74d9c43c3f8ac748725e28ab31c Mon Sep 17 00:00:00 2001 From: Timothy Carambat Date: Fri, 26 Jul 2024 14:18:40 -0700 Subject: [PATCH 06/18] Return threads for API workspace calls (#1978) * Return threads for API workspace calls * remove import --- server/endpoints/api/workspace/index.js | 34 ++++++++++++++++++++++--- server/models/workspace.js | 31 ++++++++++++++++++++++ server/swagger/openapi.json | 6 +++-- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/server/endpoints/api/workspace/index.js b/server/endpoints/api/workspace/index.js index 1974b4bc3..719b73baf 100644 --- a/server/endpoints/api/workspace/index.js +++ b/server/endpoints/api/workspace/index.js @@ -103,7 +103,8 @@ function apiWorkspaceEndpoints(app) { "openAiTemp": null, "lastUpdatedAt": "2023-08-17 00:45:03", "openAiHistory": 20, - "openAiPrompt": null + "openAiPrompt": null, + "threads": [] } ], } @@ -118,7 +119,17 @@ function apiWorkspaceEndpoints(app) { } */ try { - const workspaces = await Workspace.where(); + const workspaces = await Workspace._findMany({ + where: {}, + include: { + threads: { + select: { + user_id: true, + slug: true, + }, + }, + }, + }); response.status(200).json({ workspaces }); } catch (e) { console.error(e.message, e); @@ -152,7 +163,8 @@ function apiWorkspaceEndpoints(app) { "lastUpdatedAt": "2023-08-17 00:45:03", "openAiHistory": 20, "openAiPrompt": null, - "documents": [] + "documents": [], + "threads": [] } } } @@ -167,7 +179,21 @@ function apiWorkspaceEndpoints(app) { */ try { const { slug } = request.params; - const workspace = await Workspace.get({ slug }); + const workspace = await Workspace._findMany({ + where: { + slug: String(slug), + }, + include: { + documents: true, + threads: { + select: { + user_id: true, + slug: true, + }, + }, + }, + }); + response.status(200).json({ workspace }); } catch (e) { console.error(e.message, e); diff --git a/server/models/workspace.js b/server/models/workspace.js index d80f00ddd..b9b0c036f 100644 --- a/server/models/workspace.js +++ b/server/models/workspace.js @@ -302,6 +302,37 @@ const Workspace = { ); return; }, + + // Direct DB queries for API use only. + /** + * Generic prisma FindMany query for workspaces collections + * @param {import("../node_modules/.prisma/client/index.d.ts").Prisma.TypeMap['model']['workspaces']['operations']['findMany']['args']} prismaQuery + * @returns + */ + _findMany: async function (prismaQuery = {}) { + try { + const results = await prisma.workspaces.findMany(prismaQuery); + return results; + } catch (error) { + console.error(error.message); + return null; + } + }, + + /** + * Generic prisma query for .get of workspaces collections + * @param {import("../node_modules/.prisma/client/index.d.ts").Prisma.TypeMap['model']['workspaces']['operations']['findFirst']['args']} prismaQuery + * @returns + */ + _findFirst: async function (prismaQuery = {}) { + try { + const results = await prisma.workspaces.findFirst(prismaQuery); + return results; + } catch (error) { + console.error(error.message); + return null; + } + }, }; module.exports = { Workspace }; diff --git a/server/swagger/openapi.json b/server/swagger/openapi.json index 7831bd55e..554bd67ba 100644 --- a/server/swagger/openapi.json +++ b/server/swagger/openapi.json @@ -1476,7 +1476,8 @@ "openAiTemp": null, "lastUpdatedAt": "2023-08-17 00:45:03", "openAiHistory": 20, - "openAiPrompt": null + "openAiPrompt": null, + "threads": [] } ] } @@ -1539,7 +1540,8 @@ "lastUpdatedAt": "2023-08-17 00:45:03", "openAiHistory": 20, "openAiPrompt": null, - "documents": [] + "documents": [], + "threads": [] } } } From 296f04156455346a35cec4440239325523265d33 Mon Sep 17 00:00:00 2001 From: timothycarambat Date: Sun, 28 Jul 2024 16:29:18 -0700 Subject: [PATCH 07/18] path perplexity model ids closes #1990 --- server/utils/AiProviders/perplexity/models.js | 12 ++++++------ .../AiProviders/perplexity/scripts/chat_models.txt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/server/utils/AiProviders/perplexity/models.js b/server/utils/AiProviders/perplexity/models.js index e35068d4c..124e3ea12 100644 --- a/server/utils/AiProviders/perplexity/models.js +++ b/server/utils/AiProviders/perplexity/models.js @@ -1,7 +1,7 @@ const MODELS = { - "llama-3-sonar-small-32k-online\\*": { - id: "llama-3-sonar-small-32k-online\\*", - name: "llama-3-sonar-small-32k-online\\*", + "llama-3-sonar-small-32k-online": { + id: "llama-3-sonar-small-32k-online", + name: "llama-3-sonar-small-32k-online", maxLength: 28000, }, "llama-3-sonar-small-32k-chat": { @@ -9,9 +9,9 @@ const MODELS = { name: "llama-3-sonar-small-32k-chat", maxLength: 32768, }, - "llama-3-sonar-large-32k-online\\*": { - id: "llama-3-sonar-large-32k-online\\*", - name: "llama-3-sonar-large-32k-online\\*", + "llama-3-sonar-large-32k-online": { + id: "llama-3-sonar-large-32k-online", + name: "llama-3-sonar-large-32k-online", maxLength: 28000, }, "llama-3-sonar-large-32k-chat": { diff --git a/server/utils/AiProviders/perplexity/scripts/chat_models.txt b/server/utils/AiProviders/perplexity/scripts/chat_models.txt index e02af2551..2d2d34f72 100644 --- a/server/utils/AiProviders/perplexity/scripts/chat_models.txt +++ b/server/utils/AiProviders/perplexity/scripts/chat_models.txt @@ -1,8 +1,8 @@ | Model | Parameter Count | Context Length | Model Type | | :--------------------------------- | :-------------- | :------------- | :-------------- | -| `llama-3-sonar-small-32k-online`\* | 8B | 28,000 | Chat Completion | +| `llama-3-sonar-small-32k-online` | 8B | 28,000 | Chat Completion | | `llama-3-sonar-small-32k-chat` | 8B | 32,768 | Chat Completion | -| `llama-3-sonar-large-32k-online`\* | 70B | 28,000 | Chat Completion | +| `llama-3-sonar-large-32k-online` | 70B | 28,000 | Chat Completion | | `llama-3-sonar-large-32k-chat` | 70B | 32,768 | Chat Completion | | `llama-3-8b-instruct` | 8B | 8,192 | Chat Completion | | `llama-3-70b-instruct` | 70B | 8,192 | Chat Completion | From 13bb06013bcbe87fc4febf2571f31dc5489f3721 Mon Sep 17 00:00:00 2001 From: Timothy Carambat Date: Mon, 29 Jul 2024 11:16:00 -0700 Subject: [PATCH 08/18] Fix GroqAI picker UI bug (#1993) --- .../src/components/LLMSelection/GroqAiOptions/index.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/LLMSelection/GroqAiOptions/index.jsx b/frontend/src/components/LLMSelection/GroqAiOptions/index.jsx index c9b38ed27..4dd923d61 100644 --- a/frontend/src/components/LLMSelection/GroqAiOptions/index.jsx +++ b/frontend/src/components/LLMSelection/GroqAiOptions/index.jsx @@ -89,13 +89,16 @@ function GroqAIModelSelection({ apiKey, settings }) { name="GroqModelPref" required={true} className="border-none bg-zinc-900 border-gray-500 text-white text-sm rounded-lg block w-full p-2.5" - defaultValue={settings?.GroqModelPref} > {customModels.length > 0 && ( {customModels.map((model) => { return ( - ); From 5e73dce506a3e26ba3ad12802742a0e5003c03b0 Mon Sep 17 00:00:00 2001 From: Timothy Carambat Date: Mon, 29 Jul 2024 11:49:14 -0700 Subject: [PATCH 09/18] Enable editing of OpenRouter stream timeout for slower connections (#1994) --- .../LLMSelection/OpenRouterOptions/index.jsx | 81 ++++++++++++++----- server/models/systemSettings.js | 1 + server/utils/AiProviders/openRouter/index.js | 19 ++++- server/utils/helpers/updateENV.js | 4 + 4 files changed, 86 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/LLMSelection/OpenRouterOptions/index.jsx b/frontend/src/components/LLMSelection/OpenRouterOptions/index.jsx index 470340d2f..2b3e72b3f 100644 --- a/frontend/src/components/LLMSelection/OpenRouterOptions/index.jsx +++ b/frontend/src/components/LLMSelection/OpenRouterOptions/index.jsx @@ -1,27 +1,72 @@ import System from "@/models/system"; +import { CaretDown, CaretUp } from "@phosphor-icons/react"; import { useState, useEffect } from "react"; export default function OpenRouterOptions({ settings }) { + const [showAdvancedControls, setShowAdvancedControls] = useState(false); + return ( -
-
- - +
+
+
+ + +
+ {!settings?.credentialsOnly && ( + + )} +
+ +
+ ); +} + +function AdvancedControls({ settings }) { + const [showAdvancedControls, setShowAdvancedControls] = useState(false); + + return ( +
+ + - {!settings?.credentialsOnly && ( - - )}
); } diff --git a/server/models/systemSettings.js b/server/models/systemSettings.js index 6f5b4238d..485837506 100644 --- a/server/models/systemSettings.js +++ b/server/models/systemSettings.js @@ -424,6 +424,7 @@ const SystemSettings = { // OpenRouter Keys OpenRouterApiKey: !!process.env.OPENROUTER_API_KEY, OpenRouterModelPref: process.env.OPENROUTER_MODEL_PREF, + OpenRouterTimeout: process.env.OPENROUTER_TIMEOUT_MS, // Mistral AI (API) Keys MistralApiKey: !!process.env.MISTRAL_API_KEY, diff --git a/server/utils/AiProviders/openRouter/index.js b/server/utils/AiProviders/openRouter/index.js index 7d0ff3e3b..c7d4dfb0b 100644 --- a/server/utils/AiProviders/openRouter/index.js +++ b/server/utils/AiProviders/openRouter/index.js @@ -38,6 +38,7 @@ class OpenRouterLLM { this.embedder = embedder ?? new NativeEmbedder(); this.defaultTemp = 0.7; + this.timeout = this.#parseTimeout(); if (!fs.existsSync(cacheFolder)) fs.mkdirSync(cacheFolder, { recursive: true }); @@ -49,6 +50,22 @@ class OpenRouterLLM { console.log(`\x1b[36m[${this.constructor.name}]\x1b[0m ${text}`, ...args); } + /** + * OpenRouter has various models that never return `finish_reasons` and thus leave the stream open + * which causes issues in subsequent messages. This timeout value forces us to close the stream after + * x milliseconds. This is a configurable value via the OPENROUTER_TIMEOUT_MS value + * @returns {number} The timeout value in milliseconds (default: 500) + */ + #parseTimeout() { + this.log( + `OpenRouter timeout is set to ${process.env.OPENROUTER_TIMEOUT_MS ?? 500}ms` + ); + if (isNaN(Number(process.env.OPENROUTER_TIMEOUT_MS))) return 500; + const setValue = Number(process.env.OPENROUTER_TIMEOUT_MS); + if (setValue < 500) return 500; + return setValue; + } + // This checks if the .cached_at file has a timestamp that is more than 1Week (in millis) // from the current date. If it is, then we will refetch the API so that all the models are up // to date. @@ -161,7 +178,7 @@ class OpenRouterLLM { } handleStream(response, stream, responseProps) { - const timeoutThresholdMs = 500; + const timeoutThresholdMs = this.timeout; const { uuid = uuidv4(), sources = [] } = responseProps; return new Promise(async (resolve) => { diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js index d39941ec4..afacb7279 100644 --- a/server/utils/helpers/updateENV.js +++ b/server/utils/helpers/updateENV.js @@ -365,6 +365,10 @@ const KEY_MAPPING = { envKey: "OPENROUTER_MODEL_PREF", checks: [isNotEmpty], }, + OpenRouterTimeout: { + envKey: "OPENROUTER_TIMEOUT_MS", + checks: [], + }, // Groq Options GroqApiKey: { From d877d2b7ad30c0232f5ca15b0fffc58b06f4f23a Mon Sep 17 00:00:00 2001 From: Timothy Carambat Date: Tue, 30 Jul 2024 10:26:16 -0700 Subject: [PATCH 10/18] Add drag-and-drop to chat window (#1995) * Add drag-and-drop to chat window * add uploader icon and remove empty space text when attachments are present * color theme * color update --- .vscode/settings.json | 2 + .../ChatContainer/ChatHistory/index.jsx | 3 +- .../ChatContainer/DnDWrapper/dnd-icon.png | Bin 0 -> 2692 bytes .../ChatContainer/DnDWrapper/index.jsx | 136 ++++++++++++++ .../PromptInput/Attachments/index.jsx | 176 ++++++++++++++++++ .../ChatContainer/PromptInput/index.jsx | 7 +- .../WorkspaceChat/ChatContainer/index.jsx | 85 ++++----- frontend/src/models/workspace.js | 51 +++++ frontend/tailwind.config.js | 5 + server/endpoints/workspaces.js | 109 +++++++++++ 10 files changed, 525 insertions(+), 49 deletions(-) create mode 100644 frontend/src/components/WorkspaceChat/ChatContainer/DnDWrapper/dnd-icon.png create mode 100644 frontend/src/components/WorkspaceChat/ChatContainer/DnDWrapper/index.jsx create mode 100644 frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/Attachments/index.jsx diff --git a/.vscode/settings.json b/.vscode/settings.json index 6b47d3871..3fcc79cd5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -39,11 +39,13 @@ "openrouter", "pagerender", "Qdrant", + "royalblue", "searxng", "Serper", "Serply", "textgenwebui", "togetherai", + "Unembed", "vectordbs", "Weaviate", "Zilliz" diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx index 53cbeb64f..647d104f3 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/index.jsx @@ -17,6 +17,7 @@ export default function ChatHistory({ sendCommand, updateHistory, regenerateAssistantMessage, + hasAttachments = false, }) { const { user } = useUser(); const { threadSlug = null } = useParams(); @@ -144,7 +145,7 @@ export default function ChatHistory({ ); }; - if (history.length === 0) { + if (history.length === 0 && !hasAttachments) { return (
diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/DnDWrapper/dnd-icon.png b/frontend/src/components/WorkspaceChat/ChatContainer/DnDWrapper/dnd-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9cb0cd7cccb4d98d89220d35c8a194c8321e1ec2 GIT binary patch literal 2692 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 literal 0 HcmV?d00001 diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/DnDWrapper/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/DnDWrapper/index.jsx new file mode 100644 index 000000000..d7e4edb62 --- /dev/null +++ b/frontend/src/components/WorkspaceChat/ChatContainer/DnDWrapper/index.jsx @@ -0,0 +1,136 @@ +import { useState, useEffect } from "react"; +import { v4 } from "uuid"; +import System from "@/models/system"; +import { useDropzone } from "react-dropzone"; +import DndIcon from "./dnd-icon.png"; +import Workspace from "@/models/workspace"; +import useUser from "@/hooks/useUser"; + +export const REMOVE_ATTACHMENT_EVENT = "ATTACHMENT_REMOVE"; +export const CLEAR_ATTACHMENTS_EVENT = "ATTACHMENT_CLEAR"; + +/** + * File Attachment for automatic upload on the chat container page. + * @typedef Attachment + * @property {string} uid - unique file id. + * @property {File} file - native File object + * @property {('in_progress'|'failed'|'success')} status - the automatic upload status. + * @property {string|null} error - Error message + * @property {{id:string, location:string}|null} document - uploaded document details + */ + +export default function DnDFileUploaderWrapper({ workspace, children }) { + /** @type {[Attachment[], Function]} */ + const [files, setFiles] = useState([]); + const [ready, setReady] = useState(false); + const [dragging, setDragging] = useState(false); + const { user } = useUser(); + + useEffect(() => { + if (!!user && user.role === "default") return false; + System.checkDocumentProcessorOnline().then((status) => setReady(status)); + }, [user]); + + useEffect(() => { + window.addEventListener(REMOVE_ATTACHMENT_EVENT, handleRemove); + window.addEventListener(CLEAR_ATTACHMENTS_EVENT, resetAttachments); + + return () => { + window.removeEventListener(REMOVE_ATTACHMENT_EVENT, handleRemove); + window.removeEventListener(CLEAR_ATTACHMENTS_EVENT, resetAttachments); + }; + }, []); + + /** + * Remove file from uploader queue. + * @param {CustomEvent<{uid: string}>} event + */ + async function handleRemove(event) { + /** @type {{uid: Attachment['uid'], document: Attachment['document']}} */ + const { uid, document } = event.detail; + setFiles((prev) => prev.filter((prevFile) => prevFile.uid !== uid)); + if (!document.location) return; + await Workspace.deleteAndUnembedFile(workspace.slug, document.location); + } + + /** + * Clear queue of attached files currently in prompt box + */ + function resetAttachments() { + setFiles([]); + } + + async function onDrop(acceptedFiles, _rejections) { + setDragging(false); + /** @type {Attachment[]} */ + const newAccepted = acceptedFiles.map((file) => { + return { + uid: v4(), + file, + status: "in_progress", + error: null, + }; + }); + setFiles((prev) => [...prev, ...newAccepted]); + + for (const attachment of newAccepted) { + const formData = new FormData(); + formData.append("file", attachment.file, attachment.file.name); + Workspace.uploadAndEmbedFile(workspace.slug, formData).then( + ({ response, data }) => { + const updates = { + status: response.ok ? "success" : "failed", + error: data?.error ?? null, + document: data?.document, + }; + + setFiles((prev) => { + return prev.map( + ( + /** @type {Attachment} */ + prevFile + ) => { + if (prevFile.uid !== attachment.uid) return prevFile; + return { ...prevFile, ...updates }; + } + ); + }); + } + ); + } + } + + const { getRootProps, getInputProps } = useDropzone({ + onDrop, + disabled: !ready, + noClick: true, + noKeyboard: true, + onDragEnter: () => setDragging(true), + onDragLeave: () => setDragging(false), + }); + + return ( +
+ + + {children(files, setFiles)} +
+ ); +} diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/Attachments/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/Attachments/index.jsx new file mode 100644 index 000000000..b0032b95a --- /dev/null +++ b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/Attachments/index.jsx @@ -0,0 +1,176 @@ +import { + CircleNotch, + FileCode, + FileCsv, + FileDoc, + FileHtml, + FilePdf, + WarningOctagon, + X, +} from "@phosphor-icons/react"; +import { humanFileSize } from "@/utils/numbers"; +import { FileText } from "@phosphor-icons/react/dist/ssr"; +import { REMOVE_ATTACHMENT_EVENT } from "../../DnDWrapper"; +import { Tooltip } from "react-tooltip"; + +/** + * @param {{attachments: import("../../DnDWrapper").Attachment[]}} + * @returns + */ +export default function AttachmentManager({ attachments }) { + if (attachments.length === 0) return null; + return ( +
+ {attachments.map((attachment) => ( + + ))} +
+ ); +} + +/** + * @param {{attachment: import("../../DnDWrapper").Attachment}} + */ +function AttachmentItem({ attachment }) { + const { uid, file, status, error, document } = attachment; + const { iconBgColor, Icon } = displayFromFile(file); + + function removeFileFromQueue() { + window.dispatchEvent( + new CustomEvent(REMOVE_ATTACHMENT_EVENT, { detail: { uid, document } }) + ); + } + + if (status === "in_progress") { + return ( +
+
+ +
+
+

{file.name}

+

+ {humanFileSize(file.size)} +

+
+
+ ); + } + + if (status === "failed") { + return ( + <> +
+
+ +
+
+ +
+
+

+ {file.name} +

+

+ {error ?? "this file failed to upload"}. It will not be available + in the workspace. +

+
+
+ + + ); + } + + return ( + <> +
+
+ +
+
+ +
+
+

{file.name}

+

File embedded!

+
+
+ + + ); +} + +/** + * @param {File} file + * @returns {{iconBgColor:string, Icon: React.Component}} + */ +function displayFromFile(file) { + const extension = file?.name?.split(".")?.pop()?.toLowerCase() ?? "txt"; + switch (extension) { + case "pdf": + return { iconBgColor: "bg-magenta", Icon: FilePdf }; + case "doc": + case "docx": + return { iconBgColor: "bg-royalblue", Icon: FileDoc }; + case "html": + return { iconBgColor: "bg-warn", Icon: FileHtml }; + case "csv": + case "xlsx": + return { iconBgColor: "bg-success", Icon: FileCsv }; + case "json": + case "sql": + case "js": + case "jsx": + case "cpp": + case "c": + case "c": + return { iconBgColor: "bg-warn", Icon: FileCode }; + default: + return { iconBgColor: "bg-royalblue", Icon: FileText }; + } +} diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx index fc46fbe9c..253f158f5 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/PromptInput/index.jsx @@ -13,6 +13,7 @@ import AvailableAgentsButton, { import TextSizeButton from "./TextSizeMenu"; import SpeechToText from "./SpeechToText"; import { Tooltip } from "react-tooltip"; +import AttachmentManager from "./Attachments"; export const PROMPT_INPUT_EVENT = "set_prompt_input"; export default function PromptInput({ @@ -21,6 +22,7 @@ export default function PromptInput({ inputDisabled, buttonDisabled, sendCommand, + attachments = [], }) { const [promptInput, setPromptInput] = useState(""); const { showAgents, setShowAgents } = useAvailableAgents(); @@ -106,10 +108,11 @@ export default function PromptInput({ />
-
+
+