fix: RAG enhancements (#1965)

* fix: rag enhancements

* fix: remove auto generate prompt when user attach file

* fix: remove auto generate promp attach file via dropzone

* finalize RAG enhancements

* customize title of action sidebar panel

* remove useless import

* fix miss align retrieval toggle with switch check
This commit is contained in:
Faisal Amir 2024-02-08 14:38:54 +07:00 committed by GitHub
parent dfaab4fd28
commit 9e7348e623
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 199 additions and 82 deletions

View File

@ -1,6 +1,6 @@
.input { .input {
@apply border-border placeholder:text-muted-foreground flex h-9 w-full rounded-lg border bg-transparent px-3 py-1 transition-colors; @apply border-border placeholder:text-muted-foreground flex h-9 w-full rounded-lg border bg-transparent px-3 py-1 transition-colors;
@apply disabled:cursor-not-allowed disabled:bg-zinc-100 disabled:dark:bg-zinc-800 disabled:dark:text-zinc-600; @apply disabled:text-muted-foreground disabled:cursor-not-allowed disabled:bg-zinc-100 disabled:dark:bg-zinc-800 disabled:dark:text-zinc-600;
@apply focus-within:outline-none focus-visible:outline-0 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1; @apply focus-within:outline-none focus-visible:outline-0 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1;
@apply file:border-0 file:bg-transparent file:font-medium; @apply file:border-0 file:bg-transparent file:font-medium;
} }

View File

@ -1,6 +1,6 @@
.select { .select {
@apply placeholder:text-muted-foreground border-border flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border bg-transparent px-3 py-2 text-sm shadow-sm disabled:cursor-not-allowed [&>span]:line-clamp-1; @apply placeholder:text-muted-foreground border-border flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border bg-transparent px-3 py-2 text-sm shadow-sm disabled:cursor-not-allowed [&>span]:line-clamp-1;
@apply disabled:cursor-not-allowed disabled:bg-zinc-100 disabled:dark:bg-zinc-800 disabled:dark:text-zinc-600; @apply disabled:text-muted-foreground disabled:cursor-not-allowed disabled:bg-zinc-100 disabled:dark:bg-zinc-800 disabled:dark:text-zinc-600;
@apply focus-within:outline-none focus-visible:outline-0 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1; @apply focus-within:outline-none focus-visible:outline-0 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1;
&-caret { &-caret {

View File

@ -156,7 +156,10 @@ export default function CardSidebar({
</> </>
) : ( ) : (
<> <>
Opens <span className="lowercase">{title}.json.</span> Opens{' '}
<span className="lowercase">
{title === 'Tools' ? 'assistant' : title}.json.
</span>
&nbsp;Changes affect all new threads. &nbsp;Changes affect all new threads.
</> </>
)} )}

View File

@ -1,3 +1,5 @@
import { useContext } from 'react'
import { import {
Assistant, Assistant,
ConversationalExtension, ConversationalExtension,
@ -6,13 +8,15 @@ import {
ThreadAssistantInfo, ThreadAssistantInfo,
ThreadState, ThreadState,
Model, Model,
MessageStatus, AssistantTool,
} from '@janhq/core' } from '@janhq/core'
import { atom, useAtomValue, useSetAtom } from 'jotai' import { atom, useAtomValue, useSetAtom } from 'jotai'
import { selectedModelAtom } from '@/containers/DropdownListSidebar' import { selectedModelAtom } from '@/containers/DropdownListSidebar'
import { fileUploadAtom } from '@/containers/Providers/Jotai' import { fileUploadAtom } from '@/containers/Providers/Jotai'
import { FeatureToggleContext } from '@/context/FeatureToggle'
import { generateThreadId } from '@/utils/thread' import { generateThreadId } from '@/utils/thread'
import useRecommendedModel from './useRecommendedModel' import useRecommendedModel from './useRecommendedModel'
@ -54,6 +58,7 @@ export const useCreateNewThread = () => {
const setSelectedModel = useSetAtom(selectedModelAtom) const setSelectedModel = useSetAtom(selectedModelAtom)
const setThreadModelParams = useSetAtom(setThreadModelParamsAtom) const setThreadModelParams = useSetAtom(setThreadModelParamsAtom)
const messages = useAtomValue(getCurrentChatMessagesAtom) const messages = useAtomValue(getCurrentChatMessagesAtom)
const { experimentalFeature } = useContext(FeatureToggleContext)
const { recommendedModel, downloadedModels } = useRecommendedModel() const { recommendedModel, downloadedModels } = useRecommendedModel()
@ -72,11 +77,18 @@ export const useCreateNewThread = () => {
return null return null
} }
// modify assistant tools when experimental on, retieval toggle enabled in default
const assistantTools: AssistantTool = {
type: 'retrieval',
enabled: true,
settings: assistant.tools && assistant.tools[0].settings,
}
const createdAt = Date.now() const createdAt = Date.now()
const assistantInfo: ThreadAssistantInfo = { const assistantInfo: ThreadAssistantInfo = {
assistant_id: assistant.id, assistant_id: assistant.id,
assistant_name: assistant.name, assistant_name: assistant.name,
tools: assistant.tools, tools: experimentalFeature ? [assistantTools] : assistant.tools,
model: { model: {
id: defaultModel?.id ?? '*', id: defaultModel?.id ?? '*',
settings: defaultModel?.settings ?? {}, settings: defaultModel?.settings ?? {},

View File

@ -25,6 +25,7 @@ export const usePath = () => {
if (!selectedModel) return if (!selectedModel) return
filePath = await joinPath(['models', selectedModel.id]) filePath = await joinPath(['models', selectedModel.id])
break break
case 'Tools':
case 'Assistant': case 'Assistant':
if (!assistantId) return if (!assistantId) return
filePath = await joinPath(['assistants', assistantId]) filePath = await joinPath(['assistants', assistantId])
@ -59,6 +60,7 @@ export const usePath = () => {
filePath = await joinPath(['models', selectedModel.id, 'model.json']) filePath = await joinPath(['models', selectedModel.id, 'model.json'])
break break
case 'Assistant': case 'Assistant':
case 'Tools':
if (!assistantId) return if (!assistantId) return
filePath = await joinPath(['assistants', assistantId, 'assistant.json']) filePath = await joinPath(['assistants', assistantId, 'assistant.json'])
break break

View File

@ -112,14 +112,12 @@ const ChatInput: React.FC = () => {
const file = event.target.files?.[0] const file = event.target.files?.[0]
if (!file) return if (!file) return
setFileUpload([{ file: file, type: 'pdf' }]) setFileUpload([{ file: file, type: 'pdf' }])
setCurrentPrompt('Summarize this for me')
} }
const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0] const file = event.target.files?.[0]
if (!file) return if (!file) return
setFileUpload([{ file: file, type: 'image' }]) setFileUpload([{ file: file, type: 'image' }])
setCurrentPrompt('What do you see in this image?')
} }
const renderPreview = (fileUpload: any) => { const renderPreview = (fileUpload: any) => {

View File

@ -1,11 +1,20 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useContext } from 'react' import React, { useContext } from 'react'
import { InferenceEngine } from '@janhq/core' import {
import { Input, Textarea, Switch } from '@janhq/uikit' Input,
Textarea,
Switch,
Tooltip,
TooltipArrow,
TooltipContent,
TooltipPortal,
TooltipTrigger,
} from '@janhq/uikit'
import { atom, useAtomValue } from 'jotai' import { atom, useAtomValue } from 'jotai'
import { InfoIcon } from 'lucide-react'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import LogoMark from '@/containers/Brand/Logo/Mark' import LogoMark from '@/containers/Brand/Logo/Mark'
@ -134,15 +143,49 @@ const Sidebar: React.FC = () => {
}} }}
/> />
</div> </div>
</div>
</CardSidebar>
{experimentalFeature && ( {experimentalFeature && (
<div> <div>
{activeThread?.assistants[0]?.tools && {activeThread?.assistants[0]?.tools &&
componentDataAssistantSetting.length > 0 && ( componentDataAssistantSetting.length > 0 && (
<div className="mt-2"> <div className="mt-2">
<CardSidebar <CardSidebar title="Tools">
title="Retrieval" <div className="px-2 pt-4">
asChild <div className="mb-2">
rightAction={ <div className="flex items-center justify-between">
<label
id="retrieval"
className="inline-flex items-center font-bold text-zinc-500 dark:text-gray-300"
>
Retrieval
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon
size={16}
className="ml-2 flex-shrink-0 text-black dark:text-gray-500"
/>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent
side="top"
className="max-w-[240px]"
>
<span>
Retrieval helps the assistant use
information from files you send to it. Once
you share a file, the assistant
automatically fetches the relevant content
based on your request.
</span>
<TooltipArrow />
</TooltipContent>
</TooltipPortal>
</Tooltip>
</label>
<div className="flex items-center justify-between">
<Switch <Switch
name="retrieval" name="retrieval"
className="mr-2" className="mr-2"
@ -161,7 +204,8 @@ const Sidebar: React.FC = () => {
type: 'retrieval', type: 'retrieval',
enabled: e, enabled: e,
settings: settings:
(activeThread.assistants[0].tools && (activeThread.assistants[0]
.tools &&
activeThread.assistants[0] activeThread.assistants[0]
.tools[0]?.settings) ?? .tools[0]?.settings) ??
{}, {},
@ -172,24 +216,87 @@ const Sidebar: React.FC = () => {
}) })
}} }}
/> />
} </div>
> </div>
</div>
{activeThread?.assistants[0]?.tools[0].enabled && ( {activeThread?.assistants[0]?.tools[0].enabled && (
<div className="px-2 py-4"> <div className="pb-4 pt-2">
<div className="mb-4"> <div className="mb-4">
<div className="item-center mb-2 flex">
<label <label
id="tool-title" id="embedding-model"
className="mb-2 inline-block font-bold text-zinc-500 dark:text-gray-300" className="inline-flex font-bold text-zinc-500 dark:text-gray-300"
> >
Embedding Engine Embedding Model
</label> </label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon
size={16}
className="ml-2 flex-shrink-0 dark:text-gray-500"
/>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent
side="top"
className="max-w-[240px]"
>
<span>
Embedding model is crucial for
understanding and processing the input
text effectively by converting text to
numerical representations. Align the model
choice with your task, evaluate its
performance, and consider factors like
resource availability. Experiment to find
the best fit for your specific use case.
</span>
<TooltipArrow />
</TooltipContent>
</TooltipPortal>
</Tooltip>
</div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<label className="font-medium text-zinc-500 dark:text-gray-300"> <Input value={selectedModel?.name} disabled />
{selectedModel?.engine === </div>
InferenceEngine.openai </div>
? 'OpenAI' <div className="mb-4">
: 'Nitro'} <div className="mb-2 flex items-center">
<label
id="vector-database"
className="inline-block font-bold text-zinc-500 dark:text-gray-300"
>
Vector Database
</label> </label>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon
size={16}
className="ml-2 flex-shrink-0 dark:text-gray-500"
/>
</TooltipTrigger>
<TooltipPortal>
<TooltipContent
side="top"
className="max-w-[240px]"
>
<span>
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.
</span>
<TooltipArrow />
</TooltipContent>
</TooltipPortal>
</Tooltip>
</div>
<div className="flex items-center justify-between">
<Input value="HNSWLib" disabled />
</div> </div>
</div> </div>
<AssistantSetting <AssistantSetting
@ -197,13 +304,13 @@ const Sidebar: React.FC = () => {
/> />
</div> </div>
)} )}
</div>
</CardSidebar> </CardSidebar>
</div> </div>
)} )}
</div> </div>
)} )}
</div>
</CardSidebar>
<CardSidebar title="Model"> <CardSidebar title="Model">
<div className="px-2 pt-4"> <div className="px-2 pt-4">
<DropdownListSidebar /> <DropdownListSidebar />

View File

@ -110,11 +110,6 @@ const ChatScreen: React.FC = () => {
const imageType = files[0]?.type.includes('image') const imageType = files[0]?.type.includes('image')
setFileUpload([{ file: files[0], type: imageType ? 'image' : 'pdf' }]) setFileUpload([{ file: files[0], type: imageType ? 'image' : 'pdf' }])
setDragOver(false) setDragOver(false)
if (imageType) {
setCurrentPrompt('What do you see in this image?')
} else {
setCurrentPrompt('Summarize this for me')
}
}, },
onDropRejected: (e) => { onDropRejected: (e) => {
if ( if (