Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

index.tsx 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useCallback, useMemo, useState } from 'react'
  4. import { useBoolean } from 'ahooks'
  5. import { RiArrowDownSLine } from '@remixicon/react'
  6. import { useTranslation } from 'react-i18next'
  7. import FileIcon from '../document-file-icon'
  8. import DocumentList from './document-list'
  9. import type { DocumentItem, ParentMode, SimpleDocumentDetail } from '@/models/datasets'
  10. import { ChunkingMode } from '@/models/datasets'
  11. import {
  12. PortalToFollowElem,
  13. PortalToFollowElemContent,
  14. PortalToFollowElemTrigger,
  15. } from '@/app/components/base/portal-to-follow-elem'
  16. import cn from '@/utils/classnames'
  17. import SearchInput from '@/app/components/base/search-input'
  18. import { GeneralChunk, ParentChildChunk } from '@/app/components/base/icons/src/vender/knowledge'
  19. import { useDocumentList } from '@/service/knowledge/use-document'
  20. import Loading from '@/app/components/base/loading'
  21. type Props = {
  22. datasetId: string
  23. value: {
  24. name?: string
  25. extension?: string
  26. chunkingMode?: ChunkingMode
  27. parentMode?: ParentMode
  28. }
  29. onChange: (value: SimpleDocumentDetail) => void
  30. }
  31. const DocumentPicker: FC<Props> = ({
  32. datasetId,
  33. value,
  34. onChange,
  35. }) => {
  36. const { t } = useTranslation()
  37. const {
  38. name,
  39. extension,
  40. chunkingMode,
  41. parentMode,
  42. } = value
  43. const [query, setQuery] = useState('')
  44. const { data } = useDocumentList({
  45. datasetId,
  46. query: {
  47. keyword: query,
  48. page: 1,
  49. limit: 20,
  50. },
  51. })
  52. const documentsList = data?.data
  53. const isGeneralMode = chunkingMode === ChunkingMode.text
  54. const isParentChild = chunkingMode === ChunkingMode.parentChild
  55. const isQAMode = chunkingMode === ChunkingMode.qa
  56. const TypeIcon = isParentChild ? ParentChildChunk : GeneralChunk
  57. const [open, {
  58. set: setOpen,
  59. toggle: togglePopup,
  60. }] = useBoolean(false)
  61. const ArrowIcon = RiArrowDownSLine
  62. const handleChange = useCallback(({ id }: DocumentItem) => {
  63. onChange(documentsList?.find(item => item.id === id) as SimpleDocumentDetail)
  64. setOpen(false)
  65. }, [documentsList, onChange, setOpen])
  66. const parentModeLabel = useMemo(() => {
  67. if (!parentMode)
  68. return '--'
  69. return parentMode === 'paragraph' ? t('dataset.parentMode.paragraph') : t('dataset.parentMode.fullDoc')
  70. }, [parentMode, t])
  71. return (
  72. <PortalToFollowElem
  73. open={open}
  74. onOpenChange={setOpen}
  75. placement='bottom-start'
  76. >
  77. <PortalToFollowElemTrigger onClick={togglePopup}>
  78. <div className={cn('ml-1 flex cursor-pointer select-none items-center rounded-lg px-2 py-0.5 hover:bg-state-base-hover', open && 'bg-state-base-hover')}>
  79. <FileIcon name={name} extension={extension} size='xl' />
  80. <div className='ml-1 mr-0.5 flex flex-col items-start'>
  81. <div className='flex items-center space-x-0.5'>
  82. <span className={cn('system-md-semibold text-text-primary')}> {name || '--'}</span>
  83. <ArrowIcon className={'h-4 w-4 text-text-primary'} />
  84. </div>
  85. <div className='flex h-3 items-center space-x-0.5 text-text-tertiary'>
  86. <TypeIcon className='h-3 w-3' />
  87. <span className={cn('system-2xs-medium-uppercase', isParentChild && 'mt-0.5' /* to icon problem cause not ver align */)}>
  88. {isGeneralMode && t('dataset.chunkingMode.general')}
  89. {isQAMode && t('dataset.chunkingMode.qa')}
  90. {isParentChild && `${t('dataset.chunkingMode.parentChild')} · ${parentModeLabel}`}
  91. </span>
  92. </div>
  93. </div>
  94. </div>
  95. </PortalToFollowElemTrigger>
  96. <PortalToFollowElemContent className='z-[11]'>
  97. <div className='w-[360px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 pt-2 shadow-lg backdrop-blur-[5px]'>
  98. <SearchInput value={query} onChange={setQuery} className='mx-1' />
  99. {documentsList
  100. ? (
  101. <DocumentList
  102. className='mt-2'
  103. list={documentsList.map(d => ({
  104. id: d.id,
  105. name: d.name,
  106. extension: d.data_source_detail_dict?.upload_file?.extension || '',
  107. }))}
  108. onChange={handleChange}
  109. />
  110. )
  111. : (<div className='mt-2 flex h-[100px] w-[360px] items-center justify-center'>
  112. <Loading />
  113. </div>)}
  114. </div>
  115. </PortalToFollowElemContent>
  116. </PortalToFollowElem>
  117. )
  118. }
  119. export default React.memo(DocumentPicker)