index.tsx 10 KB

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