From 05570ea300edd9717886358c1e555b9cb07743ef Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Mon, 17 Jun 2024 21:53:45 +0700 Subject: [PATCH 01/27] chore: upgrade marked-katex-extension (#3049) --- web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/package.json b/web/package.json index e5106711c..53e04c3e6 100644 --- a/web/package.json +++ b/web/package.json @@ -28,7 +28,7 @@ "lucide-react": "^0.291.0", "marked": "^9.1.2", "marked-highlight": "^2.0.6", - "marked-katex-extension": "^5.0.1", + "marked-katex-extension": "^5.0.2", "next": "14.2.3", "next-themes": "^0.2.1", "postcss": "8.4.31", From 8077eb5cf662f84c854f44c4a58e8cebbb1cf4a4 Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Mon, 17 Jun 2024 21:54:11 +0700 Subject: [PATCH 02/27] fix: handle long word without space to avoid right panel disappears (#3048) --- .../Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/screens/Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx b/web/screens/Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx index 43d2f02c9..e11482d0e 100644 --- a/web/screens/Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx +++ b/web/screens/Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx @@ -201,7 +201,7 @@ const SimpleTextMessage: React.FC = (props) => { )} -
+
<> {props.content[0]?.type === ContentType.Image && (
From 08c60a70c2e53d6c37af6936f4814a5898d6c7ec Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 20 Jun 2024 16:34:50 +0700 Subject: [PATCH 03/27] add time weighted retrieval (#2908) * add time weighted retrieval * add missing configuration for timeWeightedVectorStore * resolving conflict * add missing configuration for timeWeightedVectorStore * resolving conflict * fix linting issues * fix build failed due to requirement for useTimeWeightedRetriever in AssistantTool * update web packages complying the new structure --------- Co-authored-by: thu --- core/src/types/assistant/assistantEntity.ts | 1 + extensions/assistant-extension/src/index.ts | 1 + .../assistant-extension/src/node/index.ts | 12 ++- .../assistant-extension/src/node/retrieval.ts | 52 +++++++++++- .../src/tools/retrieval.ts | 6 +- .../Thread/ThreadRightPanel/Tools/index.tsx | 80 ++++++++++++++++--- 6 files changed, 135 insertions(+), 17 deletions(-) diff --git a/core/src/types/assistant/assistantEntity.ts b/core/src/types/assistant/assistantEntity.ts index 733dbea8d..27592e26b 100644 --- a/core/src/types/assistant/assistantEntity.ts +++ b/core/src/types/assistant/assistantEntity.ts @@ -6,6 +6,7 @@ export type AssistantTool = { type: string enabled: boolean + useTimeWeightedRetriever?: boolean settings: any } diff --git a/extensions/assistant-extension/src/index.ts b/extensions/assistant-extension/src/index.ts index 53d3ed0d5..12441995e 100644 --- a/extensions/assistant-extension/src/index.ts +++ b/extensions/assistant-extension/src/index.ts @@ -126,6 +126,7 @@ export default class JanAssistantExtension extends AssistantExtension { { type: 'retrieval', enabled: false, + useTimeWeightedRetriever: false, settings: { top_k: 2, chunk_size: 1024, diff --git a/extensions/assistant-extension/src/node/index.ts b/extensions/assistant-extension/src/node/index.ts index 46835614d..83a4a1983 100644 --- a/extensions/assistant-extension/src/node/index.ts +++ b/extensions/assistant-extension/src/node/index.ts @@ -11,13 +11,14 @@ export function toolRetrievalUpdateTextSplitter( export async function toolRetrievalIngestNewDocument( file: string, model: string, - engine: string + engine: string, + useTimeWeighted: boolean ) { const filePath = path.join(getJanDataFolderPath(), normalizeFilePath(file)) const threadPath = path.dirname(filePath.replace('files', '')) retrieval.updateEmbeddingEngine(model, engine) return retrieval - .ingestAgentKnowledge(filePath, `${threadPath}/memory`) + .ingestAgentKnowledge(filePath, `${threadPath}/memory`, useTimeWeighted) .catch((err) => { console.error(err) }) @@ -33,8 +34,11 @@ export async function toolRetrievalLoadThreadMemory(threadId: string) { }) } -export async function toolRetrievalQueryResult(query: string) { - return retrieval.generateResult(query).catch((err) => { +export async function toolRetrievalQueryResult( + query: string, + useTimeWeighted: boolean = false +) { + return retrieval.generateResult(query, useTimeWeighted).catch((err) => { console.error(err) }) } diff --git a/extensions/assistant-extension/src/node/retrieval.ts b/extensions/assistant-extension/src/node/retrieval.ts index 52193f221..28d629aa8 100644 --- a/extensions/assistant-extension/src/node/retrieval.ts +++ b/extensions/assistant-extension/src/node/retrieval.ts @@ -2,11 +2,16 @@ import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter' import { formatDocumentsAsString } from 'langchain/util/document' import { PDFLoader } from 'langchain/document_loaders/fs/pdf' +import { TimeWeightedVectorStoreRetriever } from 'langchain/retrievers/time_weighted' +import { MemoryVectorStore } from 'langchain/vectorstores/memory' + import { HNSWLib } from 'langchain/vectorstores/hnswlib' import { OpenAIEmbeddings } from 'langchain/embeddings/openai' import { readEmbeddingEngine } from './engine' +import path from 'path' + export class Retrieval { public chunkSize: number = 100 public chunkOverlap?: number = 0 @@ -15,8 +20,25 @@ export class Retrieval { private embeddingModel?: OpenAIEmbeddings = undefined private textSplitter?: RecursiveCharacterTextSplitter + // to support time-weighted retrieval + private timeWeightedVectorStore: MemoryVectorStore + private timeWeightedretriever: any | TimeWeightedVectorStoreRetriever + constructor(chunkSize: number = 4000, chunkOverlap: number = 200) { this.updateTextSplitter(chunkSize, chunkOverlap) + + // declare time-weighted retriever and storage + this.timeWeightedVectorStore = new MemoryVectorStore( + new OpenAIEmbeddings( + { openAIApiKey: 'nitro-embedding' }, + { basePath: 'http://127.0.0.1:3928/v1' } + ) + ) + this.timeWeightedretriever = new TimeWeightedVectorStoreRetriever({ + vectorStore: this.timeWeightedVectorStore, + memoryStream: [], + searchKwargs: 2, + }) } public updateTextSplitter(chunkSize: number, chunkOverlap: number): void { @@ -44,11 +66,15 @@ export class Retrieval { openAIApiKey: settings.api_key, }) } + + // update time-weighted embedding model + this.timeWeightedVectorStore.embeddings = this.embeddingModel } public ingestAgentKnowledge = async ( filePath: string, - memoryPath: string + memoryPath: string, + useTimeWeighted: boolean ): Promise => { const loader = new PDFLoader(filePath, { splitPages: true, @@ -57,6 +83,13 @@ export class Retrieval { const doc = await loader.load() const docs = await this.textSplitter!.splitDocuments(doc) const vectorStore = await HNSWLib.fromDocuments(docs, this.embeddingModel) + + // add documents with metadata by using the time-weighted retriever in order to support time-weighted retrieval + if (useTimeWeighted && this.timeWeightedretriever) { + await ( + this.timeWeightedretriever as TimeWeightedVectorStoreRetriever + ).addDocuments(docs) + } return vectorStore.save(memoryPath) } @@ -67,10 +100,25 @@ export class Retrieval { return Promise.resolve() } - public generateResult = async (query: string): Promise => { + public generateResult = async ( + query: string, + useTimeWeighted: boolean + ): Promise => { + if (useTimeWeighted) { + if (!this.timeWeightedretriever) { + return Promise.resolve(' ') + } + // use invoke because getRelevantDocuments is deprecated + const relevantDocs = await this.timeWeightedretriever.invoke(query) + const serializedDoc = formatDocumentsAsString(relevantDocs) + return Promise.resolve(serializedDoc) + } + if (!this.retriever) { return Promise.resolve(' ') } + + // should use invoke(query) because getRelevantDocuments is deprecated const relevantDocs = await this.retriever.getRelevantDocuments(query) const serializedDoc = formatDocumentsAsString(relevantDocs) return Promise.resolve(serializedDoc) diff --git a/extensions/assistant-extension/src/tools/retrieval.ts b/extensions/assistant-extension/src/tools/retrieval.ts index a1a641941..763192287 100644 --- a/extensions/assistant-extension/src/tools/retrieval.ts +++ b/extensions/assistant-extension/src/tools/retrieval.ts @@ -37,7 +37,8 @@ export class RetrievalTool extends InferenceTool { 'toolRetrievalIngestNewDocument', docFile, data.model?.id, - data.model?.engine + data.model?.engine, + tool?.useTimeWeightedRetriever ?? false ) } else { return Promise.resolve(data) @@ -78,7 +79,8 @@ export class RetrievalTool extends InferenceTool { const retrievalResult = await executeOnMain( NODE, 'toolRetrievalQueryResult', - prompt + prompt, + tool?.useTimeWeightedRetriever ?? false ) console.debug('toolRetrievalQueryResult', retrievalResult) diff --git a/web/screens/Thread/ThreadRightPanel/Tools/index.tsx b/web/screens/Thread/ThreadRightPanel/Tools/index.tsx index 428cfbf9c..7faecc08a 100644 --- a/web/screens/Thread/ThreadRightPanel/Tools/index.tsx +++ b/web/screens/Thread/ThreadRightPanel/Tools/index.tsx @@ -66,6 +66,32 @@ const Tools = () => { [activeThread, updateThreadMetadata] ) + const onTimeWeightedRetrieverSwitchUpdate = useCallback( + (enabled: boolean) => { + if (!activeThread) return + updateThreadMetadata({ + ...activeThread, + assistants: [ + { + ...activeThread.assistants[0], + tools: [ + { + type: 'retrieval', + enabled: true, + useTimeWeightedRetriever: enabled, + settings: + (activeThread.assistants[0].tools && + activeThread.assistants[0].tools[0]?.settings) ?? + {}, + }, + ], + }, + ], + }) + }, + [activeThread, updateThreadMetadata] + ) + if (!experimentalFeature) return null return ( @@ -143,6 +169,46 @@ const Tools = () => { className="inline-block font-medium" > Vector Database + + } + content="Vector Database is crucial for efficient storage + and retrieval of embeddings. Consider your + specific task, available resources, and language + requirements. Experiment to find the best fit for + your specific use case." + /> + +
+ + onTimeWeightedRetrieverSwitchUpdate(e.target.checked) + } + /> +
+
+ +
+ +
+
+
+
+ { className="ml-2 flex-shrink-0 text-[hsl(var(--text-secondary))]" /> } - content="Vector Database is crucial for efficient storage - and retrieval of embeddings. Consider your - specific task, available resources, and language - requirements. Experiment to find the best fit for - your specific use case." + content="Time-Weighted Retriever looks at how similar + they are and how new they are. It compares + documents based on their meaning like usual, but + also considers when they were added to give + newer ones more importance." />
- -
- -
Date: Thu, 20 Jun 2024 16:42:25 +0700 Subject: [PATCH 04/27] fix: model dropdown search by configured model (#3047) --- web/containers/ModelDropdown/index.tsx | 201 ++++++++++++------------- 1 file changed, 94 insertions(+), 107 deletions(-) diff --git a/web/containers/ModelDropdown/index.tsx b/web/containers/ModelDropdown/index.tsx index b0fed7e66..ed7eed635 100644 --- a/web/containers/ModelDropdown/index.tsx +++ b/web/containers/ModelDropdown/index.tsx @@ -83,7 +83,7 @@ const ModelDropdown = ({ const filteredDownloadedModels = useMemo( () => - downloadedModels + configuredModels .filter((e) => e.name.toLowerCase().includes(searchText.toLowerCase().trim()) ) @@ -105,7 +105,7 @@ const ModelDropdown = ({ } }) .sort((a, b) => a.name.localeCompare(b.name)), - [downloadedModels, searchText, searchFilter] + [configuredModels, searchText, searchFilter] ) useEffect(() => { @@ -290,58 +290,58 @@ const ModelDropdown = ({
- {filteredDownloadedModels.filter( - (x) => x.engine === InferenceEngine.nitro - ).length !== 0 ? ( + {searchFilter !== 'remote' && (
Cortex
+
+ {filteredDownloadedModels + .filter((x) => { + if (searchText.length === 0) { + return downloadedModels.find((c) => c.id === x.id) + } else { + return x + } + }) + .filter((x) => x.engine === InferenceEngine.nitro).length !== + 0 ? (
    {filteredDownloadedModels ? filteredDownloadedModels .filter((x) => x.engine === InferenceEngine.nitro) - .map((model) => { - return ( -
  • onClickModelItem(model.id)} - > -

    - {model.name} -

    - -
  • - ) + .filter((x) => { + if (searchText.length === 0) { + return downloadedModels.find((c) => c.id === x.id) + } else { + return x + } }) - : null} -
-
- - ) : ( - <> - {searchFilter !== 'remote' && ( -
-
-
- Cortex -
- {searchText.length === 0 ? ( -
    - {featuredModel.map((model) => { + .map((model) => { const isDownloading = downloadingModels.some( (md) => md.id === model.id ) + const isdDownloaded = downloadedModels.some( + (c) => c.id === model.id + ) return (
  • { + if (isdDownloaded) { + onClickModelItem(model.id) + } + }} >

    {model.name} @@ -352,10 +352,12 @@ const ModelDropdown = ({ />

    - - {toGibibytes(model.metadata.size)} - - {!isDownloading ? ( + {!isdDownloaded && ( + + {toGibibytes(model.metadata.size)} + + )} + {!isDownloading && !isdDownloaded ? (
  • ) - })} -
- ) : ( -
    - {configuredModels - .filter((x) => x.engine === InferenceEngine.nitro) - .filter((e) => - e.name - .toLowerCase() - .includes(searchText.toLowerCase().trim()) - ) - .map((model) => { - const isDownloading = downloadingModels.some( - (md) => md.id === model.id - ) - return ( -
  • -
    -

    - {model.name} -

    - -
    -
    - - {toGibibytes(model.metadata.size)} - - {!isDownloading ? ( - downloadModel(model)} - /> - ) : ( - Object.values(downloadStates) - .filter((x) => x.modelId === model.id) - .map((item) => ( - - )) - )} -
    -
  • - ) - })} -
- )} -
-
+ }) + : null} + + ) : ( +
    + {featuredModel.map((model) => { + const isDownloading = downloadingModels.some( + (md) => md.id === model.id + ) + return ( +
  • +
    +

    + {model.name} +

    + +
    +
    + + {toGibibytes(model.metadata.size)} + + {!isDownloading ? ( + downloadModel(model)} + /> + ) : ( + Object.values(downloadStates) + .filter((x) => x.modelId === model.id) + .map((item) => ( + + )) + )} +
    +
  • + ) + })} +
)} - + )} {groupByEngine.map((engine, i) => { From 241d98f99c36b5595b791eb59880b15b5d4659a0 Mon Sep 17 00:00:00 2001 From: jan-service-account <136811300+jan-service-account@users.noreply.github.com> Date: Fri, 21 Jun 2024 19:21:59 +0700 Subject: [PATCH 05/27] Update cortex cpp nightly to version 0.4.18 (#3072) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update cortex cpp nightly to version 0.4.17 * update linux downloadnitro * c‌ortex 0.4.18 --------- Co-authored-by: github-actions[bot] Co-authored-by: Van Pham <64197333+Van-QA@users.noreply.github.com> --- extensions/inference-nitro-extension/bin/version.txt | 2 +- extensions/inference-nitro-extension/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/inference-nitro-extension/bin/version.txt b/extensions/inference-nitro-extension/bin/version.txt index 1f7716999..9bd36d9d4 100644 --- a/extensions/inference-nitro-extension/bin/version.txt +++ b/extensions/inference-nitro-extension/bin/version.txt @@ -1 +1 @@ -0.4.13 +0.4.18 diff --git a/extensions/inference-nitro-extension/package.json b/extensions/inference-nitro-extension/package.json index 21a345d6a..50294b0ab 100644 --- a/extensions/inference-nitro-extension/package.json +++ b/extensions/inference-nitro-extension/package.json @@ -10,7 +10,7 @@ "scripts": { "test": "jest", "build": "tsc --module commonjs && rollup -c rollup.config.ts", - "downloadnitro:linux": "CORTEX_VERSION=$(cat ./bin/version.txt) && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-linux-amd64-avx2.tar.gz -e --strip 1 -o ./bin/linux-cpu && chmod +x ./bin/linux-cpu/cortex-cpp && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-linux-amd64-cuda-12-0.tar.gz -e --strip 1 -o ./bin/linux-cuda-12-0 && chmod +x ./bin/linux-cuda-12-0/cortex-cpp && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-linux-amd64-cuda-11-7.tar.gz -e --strip 1 -o ./bin/linux-cuda-11-7 && chmod +x ./bin/linux-cuda-11-7/cortex-cpp && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-linux-amd64-vulkan.tar.gz -e --strip 1 -o ./bin/linux-vulkan && chmod +x ./bin/linux-vulkan/cortex-cpp", + "downloadnitro:linux": "CORTEX_VERSION=$(cat ./bin/version.txt) && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-linux-amd64-avx2.tar.gz -e --strip 1 -o ./bin/linux-cpu && chmod +x ./bin/linux-cpu/cortex-cpp && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-linux-amd64-avx2-cuda-12-0.tar.gz -e --strip 1 -o ./bin/linux-cuda-12-0 && chmod +x ./bin/linux-cuda-12-0/cortex-cpp && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-linux-amd64-avx2-cuda-11-7.tar.gz -e --strip 1 -o ./bin/linux-cuda-11-7 && chmod +x ./bin/linux-cuda-11-7/cortex-cpp && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-linux-amd64-vulkan.tar.gz -e --strip 1 -o ./bin/linux-vulkan && chmod +x ./bin/linux-vulkan/cortex-cpp", "downloadnitro:darwin": "CORTEX_VERSION=$(cat ./bin/version.txt) && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-mac-arm64.tar.gz -o ./bin/ && mkdir -p ./bin/mac-arm64 && tar -zxvf ./bin/cortex-cpp-${CORTEX_VERSION}-mac-arm64.tar.gz --strip-components=1 -C ./bin/mac-arm64 && rm -rf ./bin/cortex-cpp-${CORTEX_VERSION}-mac-arm64.tar.gz && chmod +x ./bin/mac-arm64/cortex-cpp && download https://github.com/janhq/cortex/releases/download/v${CORTEX_VERSION}/cortex-cpp-${CORTEX_VERSION}-mac-amd64.tar.gz -o ./bin/ && mkdir -p ./bin/mac-amd64 && tar -zxvf ./bin/cortex-cpp-${CORTEX_VERSION}-mac-amd64.tar.gz --strip-components=1 -C ./bin/mac-amd64 && rm -rf ./bin/cortex-cpp-${CORTEX_VERSION}-mac-amd64.tar.gz && chmod +x ./bin/mac-amd64/cortex-cpp", "downloadnitro:win32": "download.bat", "downloadnitro": "run-script-os", From e8ac8d8c019403964b46947758d41e2dd055ff21 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Wed, 26 Jun 2024 15:43:45 +0900 Subject: [PATCH 06/27] chore: update download.ts (#3088) infomation -> information --- core/src/node/helper/download.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/node/helper/download.ts b/core/src/node/helper/download.ts index b7560d100..51a0b0a8f 100644 --- a/core/src/node/helper/download.ts +++ b/core/src/node/helper/download.ts @@ -11,7 +11,7 @@ export class DownloadManager { // store the download information with key is model id public downloadProgressMap: Record = {} - // store the download infomation with key is normalized file path + // store the download information with key is normalized file path public downloadInfo: Record = {} constructor() { From 31dedb57742318a9b139b6d51c452347cd77e020 Mon Sep 17 00:00:00 2001 From: NamH Date: Wed, 26 Jun 2024 13:45:57 +0700 Subject: [PATCH 07/27] chore: cortex version update (#3098) --- extensions/inference-nitro-extension/bin/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/inference-nitro-extension/bin/version.txt b/extensions/inference-nitro-extension/bin/version.txt index 9bd36d9d4..5745cc7b1 100644 --- a/extensions/inference-nitro-extension/bin/version.txt +++ b/extensions/inference-nitro-extension/bin/version.txt @@ -1 +1 @@ -0.4.18 +0.4.16 From e77f651273edaa0706d60013a632299662387c10 Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Wed, 26 Jun 2024 13:47:24 +0700 Subject: [PATCH 08/27] fix: handle words without space (#3101) --- .../Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/screens/Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx b/web/screens/Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx index e11482d0e..721213f41 100644 --- a/web/screens/Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx +++ b/web/screens/Thread/ThreadCenterPanel/SimpleTextMessage/index.tsx @@ -201,7 +201,12 @@ const SimpleTextMessage: React.FC = (props) => { )} -
+
<> {props.content[0]?.type === ContentType.Image && (
From a2a203b40ddb4cd304514061d3101fc7cc2a00ea Mon Sep 17 00:00:00 2001 From: Faisal Amir Date: Thu, 27 Jun 2024 09:45:08 +0700 Subject: [PATCH 09/27] fix: handle long thread title without space (#3107) * fix: handle long thread title without space, and make searchbar autofocus inside model dropdown * feat: enable right click to show setting on thread items (#3108) --- web/containers/ModelDropdown/index.tsx | 11 +++- .../ModalCleanThread/index.tsx | 8 ++- .../ModalDeleteThread/index.tsx | 9 +++- .../ModalEditTitleThread/index.tsx | 8 ++- web/screens/Thread/ThreadLeftPanel/index.tsx | 53 ++++++++++++++++--- .../Thread/ThreadRightPanel/Tools/index.tsx | 2 +- 6 files changed, 79 insertions(+), 12 deletions(-) diff --git a/web/containers/ModelDropdown/index.tsx b/web/containers/ModelDropdown/index.tsx index ed7eed635..3d72df615 100644 --- a/web/containers/ModelDropdown/index.tsx +++ b/web/containers/ModelDropdown/index.tsx @@ -1,4 +1,4 @@ -import { useState, useMemo, useEffect, useCallback } from 'react' +import { useState, useMemo, useEffect, useCallback, useRef } from 'react' import { InferenceEngine } from '@janhq/core' import { Badge, Input, ScrollArea, Select, useClickOutside } from '@janhq/joi' @@ -70,7 +70,7 @@ const ModelDropdown = ({ const downloadStates = useAtomValue(modelDownloadStateAtom) const setThreadModelParams = useSetAtom(setThreadModelParamsAtom) const { updateModelParameter } = useUpdateModelParameters() - + const searchInputRef = useRef(null) const configuredModels = useAtomValue(configuredModelsAtom) const featuredModel = configuredModels.filter((x) => x.metadata.tags.includes('Featured') @@ -108,6 +108,12 @@ const ModelDropdown = ({ [configuredModels, searchText, searchFilter] ) + useEffect(() => { + if (open && searchInputRef.current) { + searchInputRef.current.focus() + } + }, [open]) + useEffect(() => { if (!activeThread) return let model = downloadedModels.find( @@ -258,6 +264,7 @@ const ModelDropdown = ({ setSearchText(e.target.value)} suffixIcon={ diff --git a/web/screens/Thread/ThreadLeftPanel/ModalCleanThread/index.tsx b/web/screens/Thread/ThreadLeftPanel/ModalCleanThread/index.tsx index f03dcc8b5..03878254f 100644 --- a/web/screens/Thread/ThreadLeftPanel/ModalCleanThread/index.tsx +++ b/web/screens/Thread/ThreadLeftPanel/ModalCleanThread/index.tsx @@ -7,9 +7,10 @@ import useDeleteThread from '@/hooks/useDeleteThread' type Props = { threadId: string + closeContextMenu?: () => void } -const ModalCleanThread = ({ threadId }: Props) => { +const ModalCleanThread = ({ threadId, closeContextMenu }: Props) => { const { cleanThread } = useDeleteThread() const onCleanThreadClick = useCallback( (e: React.MouseEvent) => { @@ -22,6 +23,11 @@ const ModalCleanThread = ({ threadId }: Props) => { return ( { + if (open && closeContextMenu) { + closeContextMenu() + } + }} trigger={
void } -const ModalDeleteThread = ({ threadId }: Props) => { +const ModalDeleteThread = ({ threadId, closeContextMenu }: Props) => { const { deleteThread } = useDeleteThread() + const onDeleteThreadClick = useCallback( (e: React.MouseEvent) => { e.stopPropagation() @@ -22,6 +24,11 @@ const ModalDeleteThread = ({ threadId }: Props) => { return ( { + if (open && closeContextMenu) { + closeContextMenu() + } + }} trigger={
void } -const ModalEditTitleThread = ({ thread }: Props) => { +const ModalEditTitleThread = ({ thread, closeContextMenu }: Props) => { const [title, setTitle] = useState(thread.title) const { updateThreadMetadata } = useCreateNewThread() @@ -30,6 +31,11 @@ const ModalEditTitleThread = ({ thread }: Props) => { return ( { + if (open && closeContextMenu) { + closeContextMenu() + } + }} trigger={
{ const setEditMessage = useSetAtom(editMessageAtom) const { recommendedModel, downloadedModels } = useRecommendedModel() + const [contextMenu, setContextMenu] = useState<{ + visible: boolean + thread?: Thread + }>({ + visible: false, + thread: undefined, + }) + const onThreadClick = useCallback( (thread: Thread) => { setActiveThread(thread) @@ -91,6 +99,21 @@ const ThreadLeftPanel = () => { } } + const onContextMenu = (event: React.MouseEvent, thread: Thread) => { + event.preventDefault() + setContextMenu({ + visible: true, + thread, + }) + } + + const closeContextMenu = () => { + setContextMenu({ + visible: false, + thread: undefined, + }) + } + return ( {threads.length === 0 ? ( @@ -124,8 +147,10 @@ const ThreadLeftPanel = () => { onClick={() => { onThreadClick(thread) }} + onContextMenu={(e) => onContextMenu(e, thread)} + onMouseLeave={closeContextMenu} > -
+

{ -
- - - +
+ + +
{activeThreadId === thread.id && ( diff --git a/web/screens/Thread/ThreadRightPanel/Tools/index.tsx b/web/screens/Thread/ThreadRightPanel/Tools/index.tsx index 7faecc08a..2b34cbb67 100644 --- a/web/screens/Thread/ThreadRightPanel/Tools/index.tsx +++ b/web/screens/Thread/ThreadRightPanel/Tools/index.tsx @@ -166,7 +166,7 @@ const Tools = () => {
- {/* setReduceTransparent(e.target.checked)} - /> */}

)} +
+
+
+
Spell checking
+
+

+ Disable if you prefer to type without spell checking interruptions + or if you are using non-standard language/terminology that the spell + checker may not recognize. +

+
+
+ setSpellCheck(e.target.checked)} + /> +
+
) } diff --git a/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx b/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx index 13187b7a4..c5f35cce8 100644 --- a/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx +++ b/web/screens/Thread/ThreadCenterPanel/ChatInput/index.tsx @@ -38,6 +38,7 @@ import ImageUploadPreview from '../ImageUploadPreview' import { showRightPanelAtom } from '@/helpers/atoms/App.atom' import { experimentalFeatureEnabledAtom } from '@/helpers/atoms/AppConfig.atom' import { getCurrentChatMessagesAtom } from '@/helpers/atoms/ChatMessage.atom' +import { spellCheckAtom } from '@/helpers/atoms/Setting.atom' import { activeThreadAtom, getActiveThreadIdAtom, @@ -52,6 +53,7 @@ const ChatInput = () => { const { stateModel } = useActiveModel() const messages = useAtomValue(getCurrentChatMessagesAtom) const [activeSetting, setActiveSetting] = useState(false) + const spellCheck = useAtomValue(spellCheckAtom) const [currentPrompt, setCurrentPrompt] = useAtom(currentPromptAtom) const { sendChatMessage } = useSendChatMessage() @@ -162,6 +164,7 @@ const ChatInput = () => { experimentalFeature && 'pl-10', activeSetting && 'pb-14 pr-16' )} + spellCheck={spellCheck} data-testid="txt-input-chat" style={{ height: activeSetting ? '100px' : '40px' }} ref={textareaRef} diff --git a/web/screens/Thread/ThreadCenterPanel/EditChatInput/index.tsx b/web/screens/Thread/ThreadCenterPanel/EditChatInput/index.tsx index 392a12c54..dbc1b9f1d 100644 --- a/web/screens/Thread/ThreadCenterPanel/EditChatInput/index.tsx +++ b/web/screens/Thread/ThreadCenterPanel/EditChatInput/index.tsx @@ -26,6 +26,7 @@ import { getCurrentChatMessagesAtom, setConvoMessagesAtom, } from '@/helpers/atoms/ChatMessage.atom' +import { spellCheckAtom } from '@/helpers/atoms/Setting.atom' import { activeThreadAtom, getActiveThreadIdAtom, @@ -45,7 +46,7 @@ const EditChatInput: React.FC = ({ message }) => { const { sendChatMessage } = useSendChatMessage() const setMessages = useSetAtom(setConvoMessagesAtom) const activeThreadId = useAtomValue(getActiveThreadIdAtom) - + const spellCheck = useAtomValue(spellCheckAtom) const [isWaitingToSend, setIsWaitingToSend] = useAtom(waitingToSendMessage) const textareaRef = useRef(null) const setEditMessage = useSetAtom(editMessageAtom) @@ -127,6 +128,7 @@ const EditChatInput: React.FC = ({ message }) => { className={twMerge('max-h-[400px] resize-none pr-20')} style={{ height: '40px' }} ref={textareaRef} + spellCheck={spellCheck} onKeyDown={onKeyDown} placeholder="Enter your message..." disabled={stateModel.loading || !activeThread} From bb171a89a4a13e2665981983c75e921851d98613 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Thu, 4 Jul 2024 11:48:18 +0530 Subject: [PATCH 16/27] fixed grammar nits (#3132) --- web/screens/Settings/Appearance/index.tsx | 7 ++----- web/screens/Settings/CoreExtensions/index.tsx | 2 +- web/screens/Settings/SettingLeftPanel/index.tsx | 2 +- web/screens/Settings/index.tsx | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/web/screens/Settings/Appearance/index.tsx b/web/screens/Settings/Appearance/index.tsx index dd0cadba0..279e0a816 100644 --- a/web/screens/Settings/Appearance/index.tsx +++ b/web/screens/Settings/Appearance/index.tsx @@ -57,7 +57,7 @@ export default function AppearanceOptions() {
Appearance

- Select of customize your interface color scheme + Select a color theme