diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 83792da7..58c42b62 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -22,7 +22,7 @@ // Terraform support "ghcr.io/devcontainers/features/terraform:1": {}, // Just a wrap to install needed packages - "ghcr.io/rocker-org/devcontainer-features/apt-packages:1": { + "ghcr.io/devcontainers-contrib/features/apt-packages:1": { // Dependencies copied from ../docker/Dockerfile plus some dev stuff "packages": [ "build-essential", diff --git a/.prettierignore b/.prettierignore index faedf325..e3b0c14e 100644 --- a/.prettierignore +++ b/.prettierignore @@ -10,3 +10,7 @@ frontend/bundleinspector.html #server server/swagger/openapi.json + +#embed +**/static/** +embed/src/utils/chat/hljs.js diff --git a/.prettierrc b/.prettierrc index 3574c1df..5e2bccfe 100644 --- a/.prettierrc +++ b/.prettierrc @@ -17,7 +17,7 @@ } }, { - "files": "*.config.js", + "files": ["*.config.js"], "options": { "semi": false, "parser": "flow", diff --git a/README.md b/README.md index 178473e1..bc3e9fdd 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@

- English · 简体中文 + English · 简体中文 · 日本語

diff --git a/collector/package.json b/collector/package.json index 785604e3..938d65e1 100644 --- a/collector/package.json +++ b/collector/package.json @@ -12,7 +12,7 @@ "scripts": { "dev": "NODE_ENV=development nodemon --ignore hotdir --ignore storage --trace-warnings index.js", "start": "NODE_ENV=production node index.js", - "lint": "yarn prettier --write ./processSingleFile ./processLink ./utils index.js" + "lint": "yarn prettier --ignore-path ../.prettierignore --write ./processSingleFile ./processLink ./utils index.js" }, "dependencies": { "@googleapis/youtube": "^9.0.0", diff --git a/collector/utils/files/mime.js b/collector/utils/files/mime.js index 635a6aa3..6cd88f82 100644 --- a/collector/utils/files/mime.js +++ b/collector/utils/files/mime.js @@ -23,6 +23,7 @@ class MimeDetector { { "text/plain": [ "ts", + "tsx", "py", "opts", "lock", @@ -35,6 +36,7 @@ class MimeDetector { "js", "lua", "pas", + "r", ], }, true diff --git a/docker/.env.example b/docker/.env.example index 6368a190..174a9d69 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -128,6 +128,12 @@ GID='1000' # VOYAGEAI_API_KEY= # EMBEDDING_MODEL_PREF='voyage-large-2-instruct' +# EMBEDDING_ENGINE='litellm' +# EMBEDDING_MODEL_PREF='text-embedding-ada-002' +# EMBEDDING_MODEL_MAX_CHUNK_LENGTH=8192 +# LITE_LLM_BASE_PATH='http://127.0.0.1:4000' +# LITE_LLM_API_KEY='sk-123abc' + ########################################### ######## Vector Database Selection ######## ########################################### diff --git a/embed/.prettierignore b/embed/.prettierignore deleted file mode 100644 index d90a3c08..00000000 --- a/embed/.prettierignore +++ /dev/null @@ -1,9 +0,0 @@ -# defaults -**/.git -**/.svn -**/.hg -**/node_modules - -**/dist -**/static/** -src/utils/chat/hljs.js diff --git a/embed/jsconfig.json b/embed/jsconfig.json index c8cc81fd..20cd368c 100644 --- a/embed/jsconfig.json +++ b/embed/jsconfig.json @@ -4,9 +4,7 @@ "target": "esnext", "jsx": "react", "paths": { - "@/*": [ - "./src/*" - ], - } - } -} \ No newline at end of file + "@/*": ["./src/*"], + }, + }, +} diff --git a/embed/package.json b/embed/package.json index eb399930..712af8e6 100644 --- a/embed/package.json +++ b/embed/package.json @@ -1,6 +1,7 @@ { "name": "anythingllm-embedded-chat", "private": false, + "license": "MIT", "type": "module", "scripts": { "dev": "nodemon -e js,jsx,css --watch src --exec \"yarn run dev:preview\"", @@ -8,7 +9,7 @@ "dev:build": "vite build && cat src/static/tailwind@3.4.1.js >> dist/anythingllm-chat-widget.js", "build": "vite build && cat src/static/tailwind@3.4.1.js >> dist/anythingllm-chat-widget.js && npx terser --compress -o dist/anythingllm-chat-widget.min.js -- dist/anythingllm-chat-widget.js", "build:publish": "yarn build && mkdir -p ../frontend/public/embed && cp -r dist/anythingllm-chat-widget.min.js ../frontend/public/embed/anythingllm-chat-widget.min.js", - "lint": "yarn prettier --write ./src" + "lint": "yarn prettier --ignore-path ../.prettierignore --write ./src" }, "dependencies": { "@microsoft/fetch-event-source": "^2.0.1", diff --git a/embed/vite.config.js b/embed/vite.config.js index 21506422..9e23c70d 100644 --- a/embed/vite.config.js +++ b/embed/vite.config.js @@ -38,7 +38,7 @@ export default defineConfig({ rollupOptions: { external: [ // Reduces transformation time by 50% and we don't even use this variant, so we can ignore. - /@phosphor-icons\/react\/dist\/ssr/, + /@phosphor-icons\/react\/dist\/ssr/ ] }, commonjsOptions: { @@ -51,7 +51,7 @@ export default defineConfig({ emptyOutDir: true, inlineDynamicImports: true, assetsDir: "", - sourcemap: 'inline', + sourcemap: "inline" }, optimizeDeps: { esbuildOptions: { @@ -60,5 +60,5 @@ export default defineConfig({ }, plugins: [] } - }, + } }) diff --git a/frontend/jsconfig.json b/frontend/jsconfig.json index c8cc81fd..e21fc376 100644 --- a/frontend/jsconfig.json +++ b/frontend/jsconfig.json @@ -4,9 +4,7 @@ "target": "esnext", "jsx": "react", "paths": { - "@/*": [ - "./src/*" - ], + "@/*": ["./src/*"] } } -} \ No newline at end of file +} diff --git a/frontend/package.json b/frontend/package.json index 11e612fc..8aa4dcfa 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,7 +7,7 @@ "start": "vite --open", "dev": "NODE_ENV=development vite --debug --host=0.0.0.0", "build": "vite build", - "lint": "yarn prettier --write ./src", + "lint": "yarn prettier --ignore-path ../.prettierignore --write ./src", "preview": "vite preview" }, "dependencies": { @@ -63,4 +63,4 @@ "tailwindcss": "^3.3.1", "vite": "^4.3.0" } -} +} \ No newline at end of file diff --git a/frontend/src/components/ChatBubble/index.jsx b/frontend/src/components/ChatBubble/index.jsx index 8d311883..c5a1f190 100644 --- a/frontend/src/components/ChatBubble/index.jsx +++ b/frontend/src/components/ChatBubble/index.jsx @@ -1,5 +1,5 @@ import React from "react"; -import Jazzicon from "../UserIcon"; +import UserIcon from "../UserIcon"; import { userFromStorage } from "@/utils/request"; import { AI_BACKGROUND_COLOR, USER_BACKGROUND_COLOR } from "@/utils/constants"; @@ -11,8 +11,7 @@ export default function ChatBubble({ message, type, popMsg }) {

- diff --git a/frontend/src/components/DefaultChat/index.jsx b/frontend/src/components/DefaultChat/index.jsx index 43ae6e7a..ae52a0d2 100644 --- a/frontend/src/components/DefaultChat/index.jsx +++ b/frontend/src/components/DefaultChat/index.jsx @@ -13,7 +13,7 @@ import { isMobile } from "react-device-detect"; import { SidebarMobileHeader } from "../Sidebar"; import ChatBubble from "../ChatBubble"; import System from "@/models/system"; -import Jazzicon from "../UserIcon"; +import UserIcon from "../UserIcon"; import { userFromStorage } from "@/utils/request"; import { AI_BACKGROUND_COLOR, USER_BACKGROUND_COLOR } from "@/utils/constants"; import useUser from "@/hooks/useUser"; @@ -46,7 +46,7 @@ export default function DefaultChatContainer() { className={`pt-10 pb-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`} >
- +
- +
- +
- @@ -151,7 +150,7 @@ export default function DefaultChatContainer() { className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`} >
- +
- @@ -213,7 +211,7 @@ export default function DefaultChatContainer() { className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`} >
- +
- @@ -275,7 +272,7 @@ export default function DefaultChatContainer() { className={`py-6 px-4 w-full flex gap-x-5 md:max-w-[80%] flex-col`} >
- +
+
+
+ + setBasePathValue(e.target.value)} + onBlur={() => setBasePath(basePathValue)} + /> +
+ +
+ + e.target.blur()} + defaultValue={settings?.EmbeddingModelMaxChunkLength} + required={false} + autoComplete="off" + /> +
+
+
+
+
+ +
+ setApiKeyValue(e.target.value)} + onBlur={() => setApiKey(apiKeyValue)} + /> +
+
+
+ ); +} + +function LiteLLMModelSelection({ settings, basePath = null, apiKey = null }) { + const [customModels, setCustomModels] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + async function findCustomModels() { + if (!basePath) { + setCustomModels([]); + setLoading(false); + return; + } + setLoading(true); + const { models } = await System.customModels( + "litellm", + typeof apiKey === "boolean" ? null : apiKey, + basePath + ); + setCustomModels(models || []); + setLoading(false); + } + findCustomModels(); + }, [basePath, apiKey]); + + if (loading || customModels.length == 0) { + return ( +
+ + +
+ ); + } + + return ( +
+
+ + +
+ +
+ ); +} + +function EmbeddingModelTooltip() { + return ( +
+ + +

+ Be sure to select a valid embedding model. Chat models are not + embedding models. See{" "} + + this page + {" "} + for more information. +

+
+
+ ); +} diff --git a/frontend/src/components/Modals/Password/index.jsx b/frontend/src/components/Modals/Password/index.jsx index 8f86b611..7010fc66 100644 --- a/frontend/src/components/Modals/Password/index.jsx +++ b/frontend/src/components/Modals/Password/index.jsx @@ -33,12 +33,12 @@ export default function PasswordModal({ mode = "single" }) { alt="login illustration" />
-
+
Logo diff --git a/frontend/src/components/SettingsSidebar/index.jsx b/frontend/src/components/SettingsSidebar/index.jsx index 2d59d0ff..297a1620 100644 --- a/frontend/src/components/SettingsSidebar/index.jsx +++ b/frontend/src/components/SettingsSidebar/index.jsx @@ -85,7 +85,7 @@ export default function SettingsSidebar() { />
{/* Header Information */} @@ -109,12 +109,14 @@ export default function SettingsSidebar() {
{/* Primary Body */} -
+
-
+
+
+
@@ -139,22 +141,21 @@ export default function SettingsSidebar() {
Instance Settings
-
+
-
+
-
-
-
+
+
+
diff --git a/frontend/src/components/Sidebar/index.jsx b/frontend/src/components/Sidebar/index.jsx index a32c0a3b..d4b4e007 100644 --- a/frontend/src/components/Sidebar/index.jsx +++ b/frontend/src/components/Sidebar/index.jsx @@ -32,34 +32,34 @@ export default function Sidebar() { Logo
-
-
- {(!user || user?.role !== "default") && ( - - )} +
+
+
+ {(!user || user?.role !== "default") && ( + + )} +
+
-
-
+
@@ -156,12 +156,9 @@ export function SidebarMobileHeader() {
{/* Primary Body */} -
+
-
+
{(!user || user?.role !== "default") && (
-
+
diff --git a/frontend/src/components/UserIcon/index.jsx b/frontend/src/components/UserIcon/index.jsx index 6cc9b57d..7fc6b8df 100644 --- a/frontend/src/components/UserIcon/index.jsx +++ b/frontend/src/components/UserIcon/index.jsx @@ -2,7 +2,7 @@ import React, { useRef, useEffect } from "react"; import JAZZ from "@metamask/jazzicon"; import usePfp from "../../hooks/usePfp"; -export default function Jazzicon({ size = 10, user, role }) { +export default function UserIcon({ size = 36, user, role }) { const { pfp } = usePfp(); const divRef = useRef(null); const seed = user?.uid diff --git a/frontend/src/components/UserIcon/workspace.png b/frontend/src/components/UserIcon/workspace.png new file mode 100644 index 00000000..537d583c Binary files /dev/null and b/frontend/src/components/UserIcon/workspace.png differ diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/EditMessage/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/EditMessage/index.jsx new file mode 100644 index 00000000..f9346b26 --- /dev/null +++ b/frontend/src/components/WorkspaceChat/ChatContainer/ChatHistory/HistoricalMessage/Actions/EditMessage/index.jsx @@ -0,0 +1,126 @@ +import { AI_BACKGROUND_COLOR, USER_BACKGROUND_COLOR } from "@/utils/constants"; +import { Pencil } from "@phosphor-icons/react"; +import { useState, useEffect, useRef } from "react"; +import { Tooltip } from "react-tooltip"; +const EDIT_EVENT = "toggle-message-edit"; + +export function useEditMessage({ chatId, role }) { + const [isEditing, setIsEditing] = useState(false); + + function onEditEvent(e) { + if (e.detail.chatId !== chatId || e.detail.role !== role) { + setIsEditing(false); + return false; + } + setIsEditing((prev) => !prev); + } + + useEffect(() => { + function listenForEdits() { + if (!chatId || !role) return; + window.addEventListener(EDIT_EVENT, onEditEvent); + } + listenForEdits(); + return () => { + window.removeEventListener(EDIT_EVENT, onEditEvent); + }; + }, [chatId, role]); + + return { isEditing, setIsEditing }; +} + +export function EditMessageAction({ chatId = null, role, isEditing }) { + function handleEditClick() { + window.dispatchEvent( + new CustomEvent(EDIT_EVENT, { detail: { chatId, role } }) + ); + } + + if (!chatId || isEditing) return null; + return ( +
+ + +
+ ); +} + +export function EditMessageForm({ + role, + chatId, + message, + adjustTextArea, + saveChanges, +}) { + const formRef = useRef(null); + function handleSaveMessage(e) { + e.preventDefault(); + const form = new FormData(e.target); + const editedMessage = form.get("editedMessage"); + saveChanges({ editedMessage, chatId, role }); + window.dispatchEvent( + new CustomEvent(EDIT_EVENT, { detail: { chatId, role } }) + ); + } + + function cancelEdits() { + window.dispatchEvent( + new CustomEvent(EDIT_EVENT, { detail: { chatId, role } }) + ); + return false; + } + + useEffect(() => { + if (!formRef || !formRef.current) return; + formRef.current.focus(); + adjustTextArea({ target: formRef.current }); + }, [formRef]); + + return ( +
+