fix: styling issues and create knowledge api from the knowledge base creation page

This commit is contained in:
Yi 2024-09-29 17:26:49 +08:00
parent 6508e7e1e4
commit bc81d2d30d
17 changed files with 107 additions and 59 deletions

View File

@ -2,7 +2,7 @@
// Libraries
import { useEffect, useMemo, useRef, useState } from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
import { useRouter } from 'next/navigation'
import { useTranslation } from 'react-i18next'
import { useDebounceFn } from 'ahooks'
import useSWR from 'swr'
@ -35,17 +35,6 @@ const Container = () => {
const { currentWorkspace } = useAppContext()
const showTagManagementModal = useTagStore(s => s.showTagManagementModal)
const { showExternalApiPanel, setShowExternalApiPanel } = useExternalApiPanel()
const searchParams = useSearchParams()
useEffect(() => {
const openPanel = searchParams.get('openExternalApiPanel')
if (openPanel === 'true') {
setTimeout(() => {
setShowExternalApiPanel(true)
window.history.replaceState({}, '', '/datasets')
}, 500)
}
}, [searchParams, setShowExternalApiPanel])
const options = useMemo(() => {
return [

View File

@ -142,7 +142,7 @@ const DatasetCard = ({
<div className='flex items-center mt-[1px] text-xs leading-[18px] text-gray-500'>
<div
className={cn('truncate', (!dataset.embedding_available || !dataset.document_count) && 'opacity-50')}
title={`${dataset.document_count}${t('dataset.documentCount')} · ${Math.round(dataset.word_count / 1000)}${t('dataset.wordCount')} · ${dataset.app_count}${t('dataset.appCount')}`}
title={dataset.provider === 'external' ? `${dataset.app_count}${t('dataset.appCount')}` : `${dataset.document_count}${t('dataset.documentCount')} · ${Math.round(dataset.word_count / 1000)}${t('dataset.wordCount')} · ${dataset.app_count}${t('dataset.appCount')}`}
>
{dataset.provider === 'external'
? <>

View File

@ -61,6 +61,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
const ref = useRef(null)
const [topK, setTopK] = useState(currentDataset?.external_retrieval_model.top_k ?? 2)
const [scoreThreshold, setScoreThreshold] = useState(currentDataset?.external_retrieval_model.score_threshold ?? 0.5)
const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(currentDataset?.external_retrieval_model.score_threshold_enabled ?? false)
const { setShowAccountSettingModal } = useModalContext()
const [loading, setLoading] = useState(false)
@ -78,11 +79,13 @@ const SettingsModal: FC<SettingsModalProps> = ({
const [isHideChangedTip, setIsHideChangedTip] = useState(false)
const isRetrievalChanged = !isEqual(retrievalConfig, localeCurrentDataset?.retrieval_model_dict) || indexMethod !== localeCurrentDataset?.indexing_technique
const handleSettingsChange = (data: { top_k?: number; score_threshold?: number }) => {
const handleSettingsChange = (data: { top_k?: number; score_threshold?: number; score_threshold_enabled?: boolean }) => {
if (data.top_k !== undefined)
setTopK(data.top_k)
if (data.score_threshold !== undefined)
setScoreThreshold(data.score_threshold)
if (data.score_threshold_enabled !== undefined)
setScoreThresholdEnabled(data.score_threshold_enabled)
}
const handleSave = async () => {
@ -122,6 +125,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
external_retrieval_model: {
top_k: topK,
score_threshold: scoreThreshold,
score_threshold_enabled: scoreThresholdEnabled,
},
retrieval_model: {
...postRetrievalConfig,
@ -287,6 +291,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
<RetrievalSettings
topK={topK}
scoreThreshold={scoreThreshold}
scoreThresholdEnabled={scoreThresholdEnabled}
onChange={handleSettingsChange}
isInRetrievalSetting={true}
/>

View File

@ -211,7 +211,7 @@ const SegmentCard: FC<ISegmentCardProps> = ({
</div>
<div className={cn('w-full bg-gray-50 group-hover:bg-white')}>
<Divider />
<div className="relative flex items-center w-full">
<div className="relative flex items-center w-full pb-1">
<DocumentTitle
name={detail?.document?.name || refSource?.title || ''}
extension={(detail?.document?.name || refSource?.title || '').split('.').pop() || 'txt'}

View File

@ -6,6 +6,8 @@ import {
import { useTranslation } from 'react-i18next'
import { useRouter } from 'next/navigation'
import { ApiConnectionMod } from '@/app/components/base/icons/src/vender/solid/development'
import { useModalContext } from '@/context/modal-context'
import { useExternalKnowledgeApi } from '@/context/external-knowledge-api-context'
type ApiItem = {
value: string
@ -22,10 +24,12 @@ type ExternalApiSelectProps = {
const ExternalApiSelect: React.FC<ExternalApiSelectProps> = ({ items, value, onSelect }) => {
const { t } = useTranslation()
const [isOpen, setIsOpen] = useState(false)
const router = useRouter()
const [selectedItem, setSelectedItem] = useState<ApiItem | null>(
items.find(item => item.value === value) || null,
)
const { setShowExternalKnowledgeAPIModal } = useModalContext()
const { mutateExternalKnowledgeApis } = useExternalKnowledgeApi()
const router = useRouter()
useEffect(() => {
const newSelectedItem = items.find(item => item.value === value) || null
@ -33,7 +37,17 @@ const ExternalApiSelect: React.FC<ExternalApiSelectProps> = ({ items, value, onS
}, [value, items])
const handleAddNewAPI = () => {
router.push('/datasets?openExternalApiPanel=true')
setShowExternalKnowledgeAPIModal({
payload: { name: '', settings: { endpoint: '', api_key: '' } },
onSaveCallback: async () => {
mutateExternalKnowledgeApis()
router.refresh()
},
onCancelCallback: () => {
mutateExternalKnowledgeApis()
},
isEditMode: false,
})
}
const handleSelect = (item: ApiItem) => {
@ -51,7 +65,7 @@ const ExternalApiSelect: React.FC<ExternalApiSelectProps> = ({ items, value, onS
>
{selectedItem
? (
<div className="flex px-2 py-1 items-center gap-0.5 self-stretch rounded-lg">
<div className="flex p-1 items-center gap-2 self-stretch rounded-lg">
<ApiConnectionMod className='text-text-secondary w-4 h-4' />
<div className='flex items-center flex-grow'>
<span className='text-components-input-text-filled text-ellipsis system-sm-regular overflow-hidden'>{selectedItem.name}</span>

View File

@ -7,6 +7,7 @@ import { useRouter } from 'next/navigation'
import ExternalApiSelect from './ExternalApiSelect'
import Input from '@/app/components/base/input'
import Button from '@/app/components/base/button'
import { useModalContext } from '@/context/modal-context'
import { useExternalKnowledgeApi } from '@/context/external-knowledge-api-context'
type ExternalApiSelectionProps = {
@ -20,6 +21,8 @@ const ExternalApiSelection: React.FC<ExternalApiSelectionProps> = ({ external_kn
const router = useRouter()
const { externalKnowledgeApiList } = useExternalKnowledgeApi()
const [selectedApiId, setSelectedApiId] = useState(external_knowledge_api_id)
const { setShowExternalKnowledgeAPIModal } = useModalContext()
const { mutateExternalKnowledgeApis } = useExternalKnowledgeApi()
const apiItems = externalKnowledgeApiList.map(api => ({
value: api.id,
@ -37,7 +40,17 @@ const ExternalApiSelection: React.FC<ExternalApiSelectionProps> = ({ external_kn
}, [apiItems, external_knowledge_api_id, external_knowledge_id, onChange])
const handleAddNewAPI = () => {
router.push('/datasets?openExternalApiPanel=true')
setShowExternalKnowledgeAPIModal({
payload: { name: '', settings: { endpoint: '', api_key: '' } },
onSaveCallback: async () => {
mutateExternalKnowledgeApis()
router.refresh()
},
onCancelCallback: () => {
mutateExternalKnowledgeApis()
},
isEditMode: false,
})
}
useEffect(() => {

View File

@ -42,7 +42,7 @@ const KnowledgeBaseInfo: React.FC<KnowledgeBaseInfoProps> = ({ name, description
value={description}
onChange={ e => handleDescriptionChange(e)}
placeholder={t('dataset.externalKnowledgeDescriptionPlaceholder') ?? ''}
className={`flex h-20 p-2 self-stretch items-start rounded-lg bg-components-input-bg-normal ${description ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder'} system-sm-regular`}
className={`flex h-20 py-2 p-3 self-stretch items-start rounded-lg bg-components-input-bg-normal ${description ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder'} system-sm-regular`}
/>
<a
className='flex py-0.5 gap-1 self-stretch'

View File

@ -1,5 +1,5 @@
import type { FC } from 'react'
import React, { useState } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import TopKItem from '@/app/components/base/param-item/top-k-item'
import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item'
@ -8,14 +8,26 @@ import cn from '@/utils/classnames'
type RetrievalSettingsProps = {
topK: number
scoreThreshold: number
scoreThresholdEnabled: boolean
isInHitTesting?: boolean
isInRetrievalSetting?: boolean
onChange: (data: { top_k?: number; score_threshold?: number }) => void
onChange: (data: { top_k?: number; score_threshold?: number; score_threshold_enabled?: boolean }) => void
}
const RetrievalSettings: FC<RetrievalSettingsProps> = ({ topK, scoreThreshold, onChange, isInHitTesting = false, isInRetrievalSetting = false }) => {
const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(false)
const RetrievalSettings: FC<RetrievalSettingsProps> = ({
topK,
scoreThreshold,
scoreThresholdEnabled,
onChange,
isInHitTesting = false,
isInRetrievalSetting = false,
}) => {
const { t } = useTranslation()
const handleScoreThresholdChange = (enabled: boolean) => {
onChange({ score_threshold_enabled: enabled })
}
return (
<div className={cn('flex flex-col gap-2 self-stretch', isInRetrievalSetting && 'w-full max-w-[480px]')}>
{!isInHitTesting && !isInRetrievalSetting && <div className='flex h-7 pt-1 flex-col gap-2 self-stretch'>
@ -44,7 +56,7 @@ const RetrievalSettings: FC<RetrievalSettingsProps> = ({ topK, scoreThreshold, o
onChange={(_key, v) => onChange({ score_threshold: v })}
enable={scoreThresholdEnabled}
hasSwitch={true}
onSwitchChange={(_key, v) => setScoreThresholdEnabled(v)}
onSwitchChange={(_key, v) => handleScoreThresholdChange(v)}
/>
</div>
</div>

View File

@ -7,5 +7,6 @@ export type CreateKnowledgeBaseReq = {
external_retrieval_model: {
top_k: number
score_threshold: number
score_threshold_enabled: boolean
}
}

View File

@ -28,6 +28,7 @@ const ExternalKnowledgeBaseCreate: React.FC<ExternalKnowledgeBaseCreateProps> =
external_retrieval_model: {
top_k: 2,
score_threshold: 0.5,
score_threshold_enabled: false,
},
provider: 'external',
@ -91,6 +92,7 @@ const ExternalKnowledgeBaseCreate: React.FC<ExternalKnowledgeBaseCreateProps> =
<RetrievalSettings
topK={formData.external_retrieval_model.top_k}
scoreThreshold={formData.external_retrieval_model.score_threshold}
scoreThresholdEnabled={formData.external_retrieval_model.score_threshold_enabled}
onChange={data => handleFormChange({
...formData,
external_retrieval_model: {

View File

@ -35,33 +35,31 @@ const HitDetail: FC<IHitDetailProps> = ({ segInfo }) => {
<div className={s.segModalContent}>{renderContent()}</div>
</div>
: <div className='overflow-x-auto'>
<div className="bg-gray-25 p-6">
<div className="flex items-center">
<SegmentIndexTag
positionId={segInfo?.position || ''}
className="w-fit mr-6"
/>
<div className={cn(s.commonIcon, s.typeSquareIcon)} />
<span className={cn('mr-6', s.numberInfo)}>
{segInfo?.word_count} {t('datasetDocuments.segment.characters')}
</span>
<div className={cn(s.commonIcon, s.targetIcon)} />
<span className={s.numberInfo}>
{segInfo?.hit_count} {t('datasetDocuments.segment.hitCount')}
</span>
</div>
<Divider />
<div className={s.segModalContent}>{renderContent()}</div>
<div className={s.keywordTitle}>
{t('datasetDocuments.segment.keywords')}
</div>
<div className={s.keywordWrapper}>
{!segInfo?.keywords?.length
? '-'
: segInfo?.keywords?.map((word, index) => {
return <div key={index} className={s.keyword}>{word}</div>
})}
</div>
<div className="flex items-center">
<SegmentIndexTag
positionId={segInfo?.position || ''}
className="w-fit mr-6"
/>
<div className={cn(s.commonIcon, s.typeSquareIcon)} />
<span className={cn('mr-6', s.numberInfo)}>
{segInfo?.word_count} {t('datasetDocuments.segment.characters')}
</span>
<div className={cn(s.commonIcon, s.targetIcon)} />
<span className={s.numberInfo}>
{segInfo?.hit_count} {t('datasetDocuments.segment.hitCount')}
</span>
</div>
<Divider />
<div className={s.segModalContent}>{renderContent()}</div>
<div className={s.keywordTitle}>
{t('datasetDocuments.segment.keywords')}
</div>
<div className={s.keywordWrapper}>
{!segInfo?.keywords?.length
? '-'
: segInfo?.keywords?.map((word, index) => {
return <div key={index} className={s.keyword}>{word}</div>
})}
</div>
</div>
)

View File

@ -218,7 +218,7 @@ const HitTesting: FC<Props> = ({ datasetId }: Props) => {
</div>
</FloatRightContainer>
<Modal
className='w-full px-10 py-6'
className='w-full'
closable
onClose={() => {
setCurrParagraph({ showModal: false })

View File

@ -9,9 +9,10 @@ import ActionButton from '@/app/components/base/action-button'
type ModifyExternalRetrievalModalProps = {
onClose: () => void
onSave: (data: { top_k: number; score_threshold: number }) => void
onSave: (data: { top_k: number; score_threshold: number; score_threshold_enabled: boolean }) => void
initialTopK: number
initialScoreThreshold: number
initialScoreThresholdEnabled: boolean
}
const ModifyExternalRetrievalModal: React.FC<ModifyExternalRetrievalModalProps> = ({
@ -19,20 +20,24 @@ const ModifyExternalRetrievalModal: React.FC<ModifyExternalRetrievalModalProps>
onSave,
initialTopK,
initialScoreThreshold,
initialScoreThresholdEnabled,
}) => {
const { t } = useTranslation()
const [topK, setTopK] = useState(initialTopK)
const [scoreThreshold, setScoreThreshold] = useState(initialScoreThreshold)
const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(initialScoreThresholdEnabled)
const handleSettingsChange = (data: { top_k?: number; score_threshold?: number }) => {
const handleSettingsChange = (data: { top_k?: number; score_threshold?: number; score_threshold_enabled?: boolean }) => {
if (data.top_k !== undefined)
setTopK(data.top_k)
if (data.score_threshold !== undefined)
setScoreThreshold(data.score_threshold)
if (data.score_threshold_enabled !== undefined)
setScoreThresholdEnabled(data.score_threshold_enabled)
}
const handleSave = () => {
onSave({ top_k: topK, score_threshold: scoreThreshold })
onSave({ top_k: topK, score_threshold: scoreThreshold, score_threshold_enabled: scoreThresholdEnabled })
onClose()
}
@ -50,6 +55,7 @@ const ModifyExternalRetrievalModal: React.FC<ModifyExternalRetrievalModalProps>
<RetrievalSettings
topK={topK}
scoreThreshold={scoreThreshold}
scoreThresholdEnabled={scoreThresholdEnabled}
onChange={handleSettingsChange}
isInHitTesting={true}
/>

View File

@ -51,9 +51,10 @@ const TextAreaWithButton = ({
const [externalRetrievalSettings, setExternalRetrievalSettings] = useState({
top_k: 2,
score_threshold: 0.5,
score_threshold_enabled: false,
})
const handleSaveExternalRetrievalSettings = (data: { top_k: number; score_threshold: number }) => {
const handleSaveExternalRetrievalSettings = (data: { top_k: number; score_threshold: number; score_threshold_enabled: boolean }) => {
setExternalRetrievalSettings(data)
setIsSettingsOpen(false)
}
@ -90,6 +91,7 @@ const TextAreaWithButton = ({
external_retrieval_model: {
top_k: externalRetrievalSettings.top_k,
score_threshold: externalRetrievalSettings.score_threshold,
score_threshold_enabled: externalRetrievalSettings.score_threshold_enabled,
},
}) as Promise<ExternalKnowledgeBaseHitTestingResponse>,
)

View File

@ -60,6 +60,7 @@ const Form = () => {
const [permission, setPermission] = useState(currentDataset?.permission)
const [topK, setTopK] = useState(currentDataset?.external_retrieval_model.top_k ?? 2)
const [scoreThreshold, setScoreThreshold] = useState(currentDataset?.external_retrieval_model.score_threshold ?? 0.5)
const [scoreThresholdEnabled, setScoreThresholdEnabled] = useState(currentDataset?.external_retrieval_model.score_threshold_enabled ?? false)
const [selectedMemberIDs, setSelectedMemberIDs] = useState<string[]>(currentDataset?.partial_member_list || [])
const [memberList, setMemberList] = useState<Member[]>([])
const [indexMethod, setIndexMethod] = useState(currentDataset?.indexing_technique)
@ -90,11 +91,13 @@ const Form = () => {
setMemberList(accounts)
}
const handleSettingsChange = (data: { top_k?: number; score_threshold?: number }) => {
const handleSettingsChange = (data: { top_k?: number; score_threshold?: number; score_threshold_enabled?: boolean }) => {
if (data.top_k !== undefined)
setTopK(data.top_k)
if (data.score_threshold !== undefined)
setScoreThreshold(data.score_threshold)
if (data.score_threshold_enabled !== undefined)
setScoreThresholdEnabled(data.score_threshold_enabled)
}
useMount(() => {
@ -141,6 +144,7 @@ const Form = () => {
external_retrieval_model: {
top_k: topK,
score_threshold: scoreThreshold,
score_threshold_enabled: scoreThresholdEnabled,
},
retrieval_model: {
...postRetrievalConfig,
@ -268,6 +272,7 @@ const Form = () => {
<RetrievalSettings
topK={topK}
scoreThreshold={scoreThreshold}
scoreThresholdEnabled={scoreThresholdEnabled}
onChange={handleSettingsChange}
isInRetrievalSetting={true}
/>

View File

@ -42,6 +42,7 @@ export type DataSet = {
external_retrieval_model: {
top_k: number
score_threshold: number
score_threshold_enabled: boolean
}
}

View File

@ -245,7 +245,7 @@ export const hitTesting: Fetcher<HitTestingResponse, { datasetId: string; queryT
return post<HitTestingResponse>(`/datasets/${datasetId}/hit-testing`, { body: { query: queryText, retrieval_model } })
}
export const externalKnowledgeBaseHitTesting: Fetcher<ExternalKnowledgeBaseHitTestingResponse, { datasetId: string; query: string; external_retrieval_model: { top_k: number; score_threshold: number } }> = ({ datasetId, query, external_retrieval_model }) => {
export const externalKnowledgeBaseHitTesting: Fetcher<ExternalKnowledgeBaseHitTestingResponse, { datasetId: string; query: string; external_retrieval_model: { top_k: number; score_threshold: number; score_threshold_enabled: boolean } }> = ({ datasetId, query, external_retrieval_model }) => {
return post<ExternalKnowledgeBaseHitTestingResponse>(`/datasets/${datasetId}/external-hit-testing`, { body: { query, external_retrieval_model } })
}