index.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React from 'react'
  4. import { useTranslation } from 'react-i18next'
  5. import {
  6. RiQuestionLine,
  7. } from '@remixicon/react'
  8. import cn from '@/utils/classnames'
  9. import TopKItem from '@/app/components/base/param-item/top-k-item'
  10. import ScoreThresholdItem from '@/app/components/base/param-item/score-threshold-item'
  11. import { RETRIEVE_METHOD } from '@/types/app'
  12. import Switch from '@/app/components/base/switch'
  13. import Tooltip from '@/app/components/base/tooltip-plus'
  14. import type { RetrievalConfig } from '@/types/app'
  15. import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
  16. import { useModelListAndDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
  17. import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
  18. import {
  19. DEFAULT_WEIGHTED_SCORE,
  20. RerankingModeEnum,
  21. WeightedScoreEnum,
  22. } from '@/models/datasets'
  23. import WeightedScore from '@/app/components/app/configuration/dataset-config/params-config/weighted-score'
  24. type Props = {
  25. type: RETRIEVE_METHOD
  26. value: RetrievalConfig
  27. onChange: (value: RetrievalConfig) => void
  28. }
  29. const RetrievalParamConfig: FC<Props> = ({
  30. type,
  31. value,
  32. onChange,
  33. }) => {
  34. const { t } = useTranslation()
  35. const canToggleRerankModalEnable = type !== RETRIEVE_METHOD.hybrid
  36. const isEconomical = type === RETRIEVE_METHOD.invertedIndex
  37. const {
  38. defaultModel: rerankDefaultModel,
  39. modelList: rerankModelList,
  40. } = useModelListAndDefaultModel(ModelTypeEnum.rerank)
  41. const isHybridSearch = type === RETRIEVE_METHOD.hybrid
  42. const rerankModel = (() => {
  43. if (value.reranking_model) {
  44. return {
  45. provider_name: value.reranking_model.reranking_provider_name,
  46. model_name: value.reranking_model.reranking_model_name,
  47. }
  48. }
  49. else if (rerankDefaultModel) {
  50. return {
  51. provider_name: rerankDefaultModel.provider.provider,
  52. model_name: rerankDefaultModel.model,
  53. }
  54. }
  55. })()
  56. const handleChangeRerankMode = (v: RerankingModeEnum) => {
  57. if (v === value.reranking_mode)
  58. return
  59. const result = {
  60. ...value,
  61. reranking_mode: v,
  62. }
  63. if (!result.weights && v === RerankingModeEnum.WeightedScore) {
  64. result.weights = {
  65. weight_type: WeightedScoreEnum.Customized,
  66. vector_setting: {
  67. vector_weight: DEFAULT_WEIGHTED_SCORE.other.semantic,
  68. embedding_provider_name: '',
  69. embedding_model_name: '',
  70. },
  71. keyword_setting: {
  72. keyword_weight: DEFAULT_WEIGHTED_SCORE.other.keyword,
  73. },
  74. }
  75. }
  76. onChange(result)
  77. }
  78. const rerankingModeOptions = [
  79. {
  80. value: RerankingModeEnum.WeightedScore,
  81. label: t('dataset.weightedScore.title'),
  82. tips: t('dataset.weightedScore.description'),
  83. },
  84. {
  85. value: RerankingModeEnum.RerankingModel,
  86. label: t('common.modelProvider.rerankModel.key'),
  87. tips: t('common.modelProvider.rerankModel.tip'),
  88. },
  89. ]
  90. return (
  91. <div>
  92. {!isEconomical && !isHybridSearch && (
  93. <div>
  94. <div className='flex h-8 items-center text-[13px] font-medium text-gray-900 space-x-2'>
  95. {canToggleRerankModalEnable && (
  96. <Switch
  97. size='md'
  98. defaultValue={value.reranking_enable}
  99. onChange={(v) => {
  100. onChange({
  101. ...value,
  102. reranking_enable: v,
  103. })
  104. }}
  105. />
  106. )}
  107. <div className='flex items-center'>
  108. <span className='mr-0.5'>{t('common.modelProvider.rerankModel.key')}</span>
  109. <Tooltip popupContent={<div className="w-[200px]">{t('common.modelProvider.rerankModel.tip')}</div>}>
  110. <RiQuestionLine className='w-[14px] h-[14px] text-gray-400' />
  111. </Tooltip>
  112. </div>
  113. </div>
  114. <ModelSelector
  115. triggerClassName={`${!value.reranking_enable && '!opacity-60 !cursor-not-allowed'}`}
  116. defaultModel={rerankModel && { provider: rerankModel.provider_name, model: rerankModel.model_name }}
  117. modelList={rerankModelList}
  118. readonly={!value.reranking_enable}
  119. onSelect={(v) => {
  120. onChange({
  121. ...value,
  122. reranking_model: {
  123. reranking_provider_name: v.provider,
  124. reranking_model_name: v.model,
  125. },
  126. })
  127. }}
  128. />
  129. </div>
  130. )}
  131. {
  132. !isHybridSearch && (
  133. <div className={cn(!isEconomical && 'mt-4', 'flex space-between space-x-6')}>
  134. <TopKItem
  135. className='grow'
  136. value={value.top_k}
  137. onChange={(_key, v) => {
  138. onChange({
  139. ...value,
  140. top_k: v,
  141. })
  142. }}
  143. enable={true}
  144. />
  145. {(!isEconomical && !(value.search_method === RETRIEVE_METHOD.fullText && !value.reranking_enable)) && (
  146. <ScoreThresholdItem
  147. className='grow'
  148. value={value.score_threshold}
  149. onChange={(_key, v) => {
  150. onChange({
  151. ...value,
  152. score_threshold: v,
  153. })
  154. }}
  155. enable={value.score_threshold_enabled}
  156. hasSwitch={true}
  157. onSwitchChange={(_key, v) => {
  158. onChange({
  159. ...value,
  160. score_threshold_enabled: v,
  161. })
  162. }}
  163. />
  164. )}
  165. </div>
  166. )
  167. }
  168. {
  169. isHybridSearch && (
  170. <>
  171. <div className='flex items-center justify-between'>
  172. {
  173. rerankingModeOptions.map(option => (
  174. <div
  175. key={option.value}
  176. className={cn(
  177. 'flex items-center justify-center mb-4 w-[calc((100%-8px)/2)] h-8 rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg cursor-pointer system-sm-medium text-text-secondary',
  178. value.reranking_mode === RerankingModeEnum.WeightedScore && option.value === RerankingModeEnum.WeightedScore && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary',
  179. value.reranking_mode !== RerankingModeEnum.WeightedScore && option.value !== RerankingModeEnum.WeightedScore && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary',
  180. )}
  181. onClick={() => handleChangeRerankMode(option.value)}
  182. >
  183. <div className='truncate'>{option.label}</div>
  184. <Tooltip
  185. popupContent={<div className='w-[200px]'>{option.tips}</div>}
  186. hideArrow
  187. >
  188. <RiQuestionLine className='ml-0.5 w-3.5 h-4.5 text-text-quaternary' />
  189. </Tooltip>
  190. </div>
  191. ))
  192. }
  193. </div>
  194. {
  195. value.reranking_mode === RerankingModeEnum.WeightedScore && (
  196. <WeightedScore
  197. value={{
  198. value: [
  199. value.weights!.vector_setting.vector_weight,
  200. value.weights!.keyword_setting.keyword_weight,
  201. ],
  202. }}
  203. onChange={(v) => {
  204. onChange({
  205. ...value,
  206. weights: {
  207. ...value.weights!,
  208. vector_setting: {
  209. ...value.weights!.vector_setting,
  210. vector_weight: v.value[0],
  211. },
  212. keyword_setting: {
  213. ...value.weights!.keyword_setting,
  214. keyword_weight: v.value[1],
  215. },
  216. },
  217. })
  218. }}
  219. />
  220. )
  221. }
  222. {
  223. value.reranking_mode !== RerankingModeEnum.WeightedScore && (
  224. <ModelSelector
  225. triggerClassName={`${!value.reranking_enable && '!opacity-60 !cursor-not-allowed'}`}
  226. defaultModel={rerankModel && { provider: rerankModel.provider_name, model: rerankModel.model_name }}
  227. modelList={rerankModelList}
  228. readonly={!value.reranking_enable}
  229. onSelect={(v) => {
  230. onChange({
  231. ...value,
  232. reranking_model: {
  233. reranking_provider_name: v.provider,
  234. reranking_model_name: v.model,
  235. },
  236. })
  237. }}
  238. />
  239. )
  240. }
  241. <div className={cn(!isEconomical && 'mt-4', 'flex space-between space-x-6')}>
  242. <TopKItem
  243. className='grow'
  244. value={value.top_k}
  245. onChange={(_key, v) => {
  246. onChange({
  247. ...value,
  248. top_k: v,
  249. })
  250. }}
  251. enable={true}
  252. />
  253. <ScoreThresholdItem
  254. className='grow'
  255. value={value.score_threshold}
  256. onChange={(_key, v) => {
  257. onChange({
  258. ...value,
  259. score_threshold: v,
  260. })
  261. }}
  262. enable={value.score_threshold_enabled}
  263. hasSwitch={true}
  264. onSwitchChange={(_key, v) => {
  265. onChange({
  266. ...value,
  267. score_threshold_enabled: v,
  268. })
  269. }}
  270. />
  271. </div>
  272. </>
  273. )
  274. }
  275. </div>
  276. )
  277. }
  278. export default React.memo(RetrievalParamConfig)