Commit 76dd849d authored by JzoNg's avatar JzoNg

feat: language selection supported in segmentation

parent 2b5bc9e0
...@@ -9,6 +9,7 @@ type IPopover = { ...@@ -9,6 +9,7 @@ type IPopover = {
position?: 'bottom' | 'br' position?: 'bottom' | 'br'
btnElement?: string | React.ReactNode btnElement?: string | React.ReactNode
btnClassName?: string | ((open: boolean) => string) btnClassName?: string | ((open: boolean) => string)
manualClose?: boolean
} }
const timeoutDuration = 100 const timeoutDuration = 100
...@@ -20,6 +21,7 @@ export default function CustomPopover({ ...@@ -20,6 +21,7 @@ export default function CustomPopover({
btnElement, btnElement,
className, className,
btnClassName, btnClassName,
manualClose,
}: IPopover) { }: IPopover) {
const buttonRef = useRef<HTMLButtonElement>(null) const buttonRef = useRef<HTMLButtonElement>(null)
const timeOutRef = useRef<NodeJS.Timeout | null>(null) const timeOutRef = useRef<NodeJS.Timeout | null>(null)
...@@ -65,28 +67,36 @@ export default function CustomPopover({ ...@@ -65,28 +67,36 @@ export default function CustomPopover({
leaveTo="opacity-0 translate-y-1" leaveTo="opacity-0 translate-y-1"
> >
<Popover.Panel <Popover.Panel
className={`${s.popupPanel} ${position === 'br' ? 'right-0' : 'transform -translate-x-1/2 left-1/2'} ${className}`} className={`${s.popupPanel} ${position === 'br' ? 'right-0' : 'translate-x-1/2 left-1/2'} ${className}`}
{...(trigger !== 'hover' {...(trigger !== 'hover'
? {} ? {}
: { : {
onMouseLeave: () => onMouseLeave(open), onMouseLeave: () => onMouseLeave(open),
onMouseEnter: () => onMouseEnter(open), onMouseEnter: () => onMouseEnter(open),
}) })
}> }
<div >
className={s.panelContainer} {({ close }) => (
{...(trigger !== 'hover' <div
? {} className={s.panelContainer}
: { {...(trigger !== 'hover'
onMouseLeave: () => onMouseLeave(open), ? {}
onMouseEnter: () => onMouseEnter(open), : {
}) onMouseLeave: () => onMouseLeave(open),
} onMouseEnter: () => onMouseEnter(open),
> })
{cloneElement(htmlContent as React.ReactElement, { }
onClose: () => onMouseLeave(open), >
})} {cloneElement(htmlContent as React.ReactElement, {
</div> onClose: () => onMouseLeave(open),
...(manualClose
? {
onClick: close,
}
: {}),
})}
</div>
)}
</Popover.Panel> </Popover.Panel>
</Transition> </Transition>
</div> </div>
......
...@@ -2,12 +2,14 @@ ...@@ -2,12 +2,14 @@
'use client' 'use client'
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react' import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { useBoolean } from 'ahooks' import { useBoolean } from 'ahooks'
import { XMarkIcon } from '@heroicons/react/20/solid' import { XMarkIcon } from '@heroicons/react/20/solid'
import cn from 'classnames' import cn from 'classnames'
import Link from 'next/link' import Link from 'next/link'
import { groupBy } from 'lodash-es' import { groupBy } from 'lodash-es'
import PreviewItem, { PreviewType } from './preview-item' import PreviewItem, { PreviewType } from './preview-item'
import LanguageSelect from './language-select'
import s from './index.module.css' import s from './index.module.css'
import type { CreateDocumentReq, File, FullDocumentDetail, FileIndexingEstimateResponse as IndexingEstimateResponse, NotionInfo, PreProcessingRule, Rules, createDocumentResponse } from '@/models/datasets' import type { CreateDocumentReq, File, FullDocumentDetail, FileIndexingEstimateResponse as IndexingEstimateResponse, NotionInfo, PreProcessingRule, Rules, createDocumentResponse } from '@/models/datasets'
import { import {
...@@ -26,7 +28,10 @@ import { DataSourceType } from '@/models/datasets' ...@@ -26,7 +28,10 @@ import { DataSourceType } from '@/models/datasets'
import NotionIcon from '@/app/components/base/notion-icon' import NotionIcon from '@/app/components/base/notion-icon'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import { MessageChatSquare } from '@/app/components/base/icons/src/public/common' import { MessageChatSquare } from '@/app/components/base/icons/src/public/common'
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
import { useDatasetDetailContext } from '@/context/dataset-detail' import { useDatasetDetailContext } from '@/context/dataset-detail'
import I18n from '@/context/i18n'
import { IS_CE_EDITION } from '@/config'
type Page = DataSourceNotionPage & { workspace_id: string } type Page = DataSourceNotionPage & { workspace_id: string }
...@@ -77,6 +82,8 @@ const StepTwo = ({ ...@@ -77,6 +82,8 @@ const StepTwo = ({
onCancel, onCancel,
}: StepTwoProps) => { }: StepTwoProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { locale } = useContext(I18n)
const { mutateDatasetRes } = useDatasetDetailContext() const { mutateDatasetRes } = useDatasetDetailContext()
const scrollRef = useRef<HTMLDivElement>(null) const scrollRef = useRef<HTMLDivElement>(null)
const [scrolled, setScrolled] = useState(false) const [scrolled, setScrolled] = useState(false)
...@@ -97,6 +104,8 @@ const StepTwo = ({ ...@@ -97,6 +104,8 @@ const StepTwo = ({
const [docForm, setDocForm] = useState<DocForm | string>( const [docForm, setDocForm] = useState<DocForm | string>(
datasetId && documentDetail ? documentDetail.doc_form : DocForm.TEXT, datasetId && documentDetail ? documentDetail.doc_form : DocForm.TEXT,
) )
const [docLanguage, setDocLanguage] = useState<string>(locale === 'en' ? 'English' : 'Chinese')
const [QATipHide, setQATipHide] = useState(false)
const [previewSwitched, setPreviewSwitched] = useState(false) const [previewSwitched, setPreviewSwitched] = useState(false)
const [showPreview, { setTrue: setShowPreview, setFalse: hidePreview }] = useBoolean() const [showPreview, { setTrue: setShowPreview, setFalse: hidePreview }] = useBoolean()
const [customFileIndexingEstimate, setCustomFileIndexingEstimate] = useState<IndexingEstimateResponse | null>(null) const [customFileIndexingEstimate, setCustomFileIndexingEstimate] = useState<IndexingEstimateResponse | null>(null)
...@@ -229,6 +238,7 @@ const StepTwo = ({ ...@@ -229,6 +238,7 @@ const StepTwo = ({
indexing_technique: getIndexing_technique(), indexing_technique: getIndexing_technique(),
process_rule: getProcessRule(), process_rule: getProcessRule(),
doc_form: docForm, doc_form: docForm,
doc_language: docLanguage,
} }
} }
if (dataSourceType === DataSourceType.NOTION) { if (dataSourceType === DataSourceType.NOTION) {
...@@ -240,6 +250,7 @@ const StepTwo = ({ ...@@ -240,6 +250,7 @@ const StepTwo = ({
indexing_technique: getIndexing_technique(), indexing_technique: getIndexing_technique(),
process_rule: getProcessRule(), process_rule: getProcessRule(),
doc_form: docForm, doc_form: docForm,
doc_language: docLanguage,
} }
} }
return params return params
...@@ -251,6 +262,7 @@ const StepTwo = ({ ...@@ -251,6 +262,7 @@ const StepTwo = ({
params = { params = {
original_document_id: documentDetail?.id, original_document_id: documentDetail?.id,
doc_form: docForm, doc_form: docForm,
doc_language: docLanguage,
process_rule: getProcessRule(), process_rule: getProcessRule(),
} as CreateDocumentReq } as CreateDocumentReq
} }
...@@ -265,6 +277,7 @@ const StepTwo = ({ ...@@ -265,6 +277,7 @@ const StepTwo = ({
indexing_technique: getIndexing_technique(), indexing_technique: getIndexing_technique(),
process_rule: getProcessRule(), process_rule: getProcessRule(),
doc_form: docForm, doc_form: docForm,
doc_language: docLanguage,
} as CreateDocumentReq } as CreateDocumentReq
if (dataSourceType === DataSourceType.FILE) { if (dataSourceType === DataSourceType.FILE) {
params.data_source.info_list.file_info_list = { params.data_source.info_list.file_info_list = {
...@@ -347,6 +360,10 @@ const StepTwo = ({ ...@@ -347,6 +360,10 @@ const StepTwo = ({
setDocForm(DocForm.TEXT) setDocForm(DocForm.TEXT)
} }
const handleSelect = (language: string) => {
setDocLanguage(language)
}
const changeToEconomicalType = () => { const changeToEconomicalType = () => {
if (!hasSetIndexType) { if (!hasSetIndexType) {
setIndexType(IndexingType.ECONOMICAL) setIndexType(IndexingType.ECONOMICAL)
...@@ -572,22 +589,33 @@ const StepTwo = ({ ...@@ -572,22 +589,33 @@ const StepTwo = ({
<Link className='text-[#155EEF]' href={`/datasets/${datasetId}/settings`}>{t('datasetCreation.stepTwo.datasetSettingLink')}</Link> <Link className='text-[#155EEF]' href={`/datasets/${datasetId}/settings`}>{t('datasetCreation.stepTwo.datasetSettingLink')}</Link>
</div> </div>
)} )}
{indexType === IndexingType.QUALIFIED && ( {!IS_CE_EDITION && indexType === IndexingType.QUALIFIED && (
<div className='flex justify-between items-center mt-3 px-5 py-4 rounded-xl bg-gray-50 border border-gray-100'> <div className='mt-3 rounded-xl bg-gray-50 border border-gray-100'>
<div className='flex justify-center items-center w-8 h-8 rounded-lg bg-indigo-50'> <div className='flex justify-between items-center px-5 py-4'>
<MessageChatSquare className='w-4 h-4' /> <div className='flex justify-center items-center w-8 h-8 rounded-lg bg-indigo-50'>
</div> <MessageChatSquare className='w-4 h-4' />
<div className='grow mx-3'> </div>
<div className='mb-[2px] text-md font-medium text-gray-900'>{t('datasetCreation.stepTwo.QATitle')}</div> <div className='grow mx-3'>
<div className='text-[13px] leading-[18px] text-gray-500'>{t('datasetCreation.stepTwo.QATip')}</div> <div className='mb-[2px] text-md font-medium text-gray-900'>{t('datasetCreation.stepTwo.QATitle')}</div>
</div> <div className='inline-flex items-center text-[13px] leading-[18px] text-gray-500'>
<div className='shrink-0'> <span className='pr-1'>{t('datasetCreation.stepTwo.QALanguage')}</span>
<Switch <LanguageSelect currentLanguage={docLanguage} onSelect={handleSelect} />
defaultValue={docForm === DocForm.QA} </div>
onChange={handleSwitch} </div>
size='md' <div className='shrink-0'>
/> <Switch
defaultValue={docForm === DocForm.QA}
onChange={handleSwitch}
size='md'
/>
</div>
</div> </div>
{docForm === DocForm.QA && !QATipHide && (
<div className='flex justify-between items-center px-5 py-2 bg-orange-50 border-t border-amber-100 rounded-b-xl text-[13px] leading-[18px] text-medium text-amber-500'>
{t('datasetCreation.stepTwo.QATip')}
<XClose className='w-4 h-4 text-gray-500 cursor-pointer' onClick={() => setQATipHide(true)} />
</div>
)}
</div> </div>
)} )}
<div className={s.source}> <div className={s.source}>
......
'use client'
import type { FC } from 'react'
import React from 'react'
import cn from 'classnames'
import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
import Popover from '@/app/components/base/popover'
export type ILanguageSelectProps = {
currentLanguage: string
onSelect: (language: string) => void
}
const LanguageSelect: FC<ILanguageSelectProps> = ({
currentLanguage,
onSelect,
}) => {
return (
<Popover
manualClose
trigger='click'
htmlContent={
<div className='w-full py-1'>
<div className='py-2 px-3 mx-1 flex items-center gap-2 hover:bg-gray-100 rounded-lg cursor-pointer text-gray-700 text-sm' onClick={() => onSelect('English')}>English</div>
<div className='py-2 px-3 mx-1 flex items-center gap-2 hover:bg-gray-100 rounded-lg cursor-pointer text-gray-700 text-sm' onClick={() => onSelect('Chinese')}>简体中文</div>
</div>
}
btnElement={
<div className='inline-flex items-center'>
<span className='pr-[2px] text-xs leading-[18px] font-medium'>{currentLanguage === 'English' ? 'English' : '简体中文'}</span>
<ChevronDown className='w-3 h-3 opacity-60' />
</div>
}
btnClassName={open => cn('!border-0 !px-0 !py-0 !bg-inherit !hover:bg-inherit', open ? 'text-blue-600' : 'text-gray-500')}
className='!w-[120px] h-fit !z-20 !translate-x-0 !left-[-16px]'
/>
)
}
export default React.memo(LanguageSelect)
...@@ -75,6 +75,7 @@ const translation = { ...@@ -75,6 +75,7 @@ const translation = {
economicalTip: 'Use offline vector engines, keyword indexes, etc. to reduce accuracy without spending tokens', economicalTip: 'Use offline vector engines, keyword indexes, etc. to reduce accuracy without spending tokens',
QATitle: 'Segmenting in Question & Answer format', QATitle: 'Segmenting in Question & Answer format',
QATip: 'Enable this option will consume more tokens', QATip: 'Enable this option will consume more tokens',
QALanguage: 'Segment using',
emstimateCost: 'Estimation', emstimateCost: 'Estimation',
emstimateSegment: 'Estimated segments', emstimateSegment: 'Estimated segments',
segmentCount: 'segments', segmentCount: 'segments',
......
...@@ -75,6 +75,7 @@ const translation = { ...@@ -75,6 +75,7 @@ const translation = {
economicalTip: '使用离线的向量引擎、关键词索引等方式,降低了准确度但无需花费 Token', economicalTip: '使用离线的向量引擎、关键词索引等方式,降低了准确度但无需花费 Token',
QATitle: '采用 Q&A 分段模式', QATitle: '采用 Q&A 分段模式',
QATip: '开启后将会消耗额外的 token', QATip: '开启后将会消耗额外的 token',
QALanguage: '分段使用',
emstimateCost: '执行嵌入预估消耗', emstimateCost: '执行嵌入预估消耗',
emstimateSegment: '预估分段数', emstimateSegment: '预估分段数',
segmentCount: '段', segmentCount: '段',
......
...@@ -179,6 +179,7 @@ export type CreateDocumentReq = { ...@@ -179,6 +179,7 @@ export type CreateDocumentReq = {
original_document_id?: string original_document_id?: string
indexing_technique?: string indexing_technique?: string
doc_form: 'text_model' | 'qa_model' doc_form: 'text_model' | 'qa_model'
doc_language: string
data_source: DataSource data_source: DataSource
process_rule: ProcessRule process_rule: ProcessRule
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment