ParameterControl.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. Copyright (C) 2025 QuantumNous
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>.
  13. For commercial licensing, please contact support@quantumnous.com
  14. */
  15. import React from 'react';
  16. import {
  17. Input,
  18. Slider,
  19. Typography,
  20. Button,
  21. Tag,
  22. } from '@douyinfe/semi-ui';
  23. import {
  24. Hash,
  25. Thermometer,
  26. Target,
  27. Repeat,
  28. Ban,
  29. Shuffle,
  30. Check,
  31. X,
  32. } from 'lucide-react';
  33. const ParameterControl = ({
  34. inputs,
  35. parameterEnabled,
  36. onInputChange,
  37. onParameterToggle,
  38. disabled = false,
  39. }) => {
  40. return (
  41. <>
  42. {/* Temperature */}
  43. <div className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.temperature || disabled ? 'opacity-50' : ''}`}>
  44. <div className="flex items-center justify-between mb-2">
  45. <div className="flex items-center gap-2">
  46. <Thermometer size={16} className="text-gray-500" />
  47. <Typography.Text strong className="text-sm">
  48. Temperature
  49. </Typography.Text>
  50. <Tag size="small" shape='circle'>
  51. {inputs.temperature}
  52. </Tag>
  53. </div>
  54. <Button
  55. theme={parameterEnabled.temperature ? 'solid' : 'borderless'}
  56. type={parameterEnabled.temperature ? 'primary' : 'tertiary'}
  57. size="small"
  58. icon={parameterEnabled.temperature ? <Check size={10} /> : <X size={10} />}
  59. onClick={() => onParameterToggle('temperature')}
  60. className="!rounded-full !w-4 !h-4 !p-0 !min-w-0"
  61. disabled={disabled}
  62. />
  63. </div>
  64. <Typography.Text className="text-xs text-gray-500 mb-2">
  65. 控制输出的随机性和创造性
  66. </Typography.Text>
  67. <Slider
  68. step={0.1}
  69. min={0.1}
  70. max={1}
  71. value={inputs.temperature}
  72. onChange={(value) => onInputChange('temperature', value)}
  73. className="mt-2"
  74. disabled={!parameterEnabled.temperature || disabled}
  75. />
  76. </div>
  77. {/* Top P */}
  78. <div className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.top_p || disabled ? 'opacity-50' : ''}`}>
  79. <div className="flex items-center justify-between mb-2">
  80. <div className="flex items-center gap-2">
  81. <Target size={16} className="text-gray-500" />
  82. <Typography.Text strong className="text-sm">
  83. Top P
  84. </Typography.Text>
  85. <Tag size="small" shape='circle'>
  86. {inputs.top_p}
  87. </Tag>
  88. </div>
  89. <Button
  90. theme={parameterEnabled.top_p ? 'solid' : 'borderless'}
  91. type={parameterEnabled.top_p ? 'primary' : 'tertiary'}
  92. size="small"
  93. icon={parameterEnabled.top_p ? <Check size={10} /> : <X size={10} />}
  94. onClick={() => onParameterToggle('top_p')}
  95. className="!rounded-full !w-4 !h-4 !p-0 !min-w-0"
  96. disabled={disabled}
  97. />
  98. </div>
  99. <Typography.Text className="text-xs text-gray-500 mb-2">
  100. 核采样,控制词汇选择的多样性
  101. </Typography.Text>
  102. <Slider
  103. step={0.1}
  104. min={0.1}
  105. max={1}
  106. value={inputs.top_p}
  107. onChange={(value) => onInputChange('top_p', value)}
  108. className="mt-2"
  109. disabled={!parameterEnabled.top_p || disabled}
  110. />
  111. </div>
  112. {/* Frequency Penalty */}
  113. <div className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.frequency_penalty || disabled ? 'opacity-50' : ''}`}>
  114. <div className="flex items-center justify-between mb-2">
  115. <div className="flex items-center gap-2">
  116. <Repeat size={16} className="text-gray-500" />
  117. <Typography.Text strong className="text-sm">
  118. Frequency Penalty
  119. </Typography.Text>
  120. <Tag size="small" shape='circle'>
  121. {inputs.frequency_penalty}
  122. </Tag>
  123. </div>
  124. <Button
  125. theme={parameterEnabled.frequency_penalty ? 'solid' : 'borderless'}
  126. type={parameterEnabled.frequency_penalty ? 'primary' : 'tertiary'}
  127. size="small"
  128. icon={parameterEnabled.frequency_penalty ? <Check size={10} /> : <X size={10} />}
  129. onClick={() => onParameterToggle('frequency_penalty')}
  130. className="!rounded-full !w-4 !h-4 !p-0 !min-w-0"
  131. disabled={disabled}
  132. />
  133. </div>
  134. <Typography.Text className="text-xs text-gray-500 mb-2">
  135. 频率惩罚,减少重复词汇的出现
  136. </Typography.Text>
  137. <Slider
  138. step={0.1}
  139. min={-2}
  140. max={2}
  141. value={inputs.frequency_penalty}
  142. onChange={(value) => onInputChange('frequency_penalty', value)}
  143. className="mt-2"
  144. disabled={!parameterEnabled.frequency_penalty || disabled}
  145. />
  146. </div>
  147. {/* Presence Penalty */}
  148. <div className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.presence_penalty || disabled ? 'opacity-50' : ''}`}>
  149. <div className="flex items-center justify-between mb-2">
  150. <div className="flex items-center gap-2">
  151. <Ban size={16} className="text-gray-500" />
  152. <Typography.Text strong className="text-sm">
  153. Presence Penalty
  154. </Typography.Text>
  155. <Tag size="small" shape='circle'>
  156. {inputs.presence_penalty}
  157. </Tag>
  158. </div>
  159. <Button
  160. theme={parameterEnabled.presence_penalty ? 'solid' : 'borderless'}
  161. type={parameterEnabled.presence_penalty ? 'primary' : 'tertiary'}
  162. size="small"
  163. icon={parameterEnabled.presence_penalty ? <Check size={10} /> : <X size={10} />}
  164. onClick={() => onParameterToggle('presence_penalty')}
  165. className="!rounded-full !w-4 !h-4 !p-0 !min-w-0"
  166. disabled={disabled}
  167. />
  168. </div>
  169. <Typography.Text className="text-xs text-gray-500 mb-2">
  170. 存在惩罚,鼓励讨论新话题
  171. </Typography.Text>
  172. <Slider
  173. step={0.1}
  174. min={-2}
  175. max={2}
  176. value={inputs.presence_penalty}
  177. onChange={(value) => onInputChange('presence_penalty', value)}
  178. className="mt-2"
  179. disabled={!parameterEnabled.presence_penalty || disabled}
  180. />
  181. </div>
  182. {/* MaxTokens */}
  183. <div className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.max_tokens || disabled ? 'opacity-50' : ''}`}>
  184. <div className="flex items-center justify-between mb-2">
  185. <div className="flex items-center gap-2">
  186. <Hash size={16} className="text-gray-500" />
  187. <Typography.Text strong className="text-sm">
  188. Max Tokens
  189. </Typography.Text>
  190. </div>
  191. <Button
  192. theme={parameterEnabled.max_tokens ? 'solid' : 'borderless'}
  193. type={parameterEnabled.max_tokens ? 'primary' : 'tertiary'}
  194. size="small"
  195. icon={parameterEnabled.max_tokens ? <Check size={10} /> : <X size={10} />}
  196. onClick={() => onParameterToggle('max_tokens')}
  197. className="!rounded-full !w-4 !h-4 !p-0 !min-w-0"
  198. disabled={disabled}
  199. />
  200. </div>
  201. <Input
  202. placeholder='MaxTokens'
  203. name='max_tokens'
  204. required
  205. autoComplete='new-password'
  206. defaultValue={0}
  207. value={inputs.max_tokens}
  208. onChange={(value) => onInputChange('max_tokens', value)}
  209. className="!rounded-lg"
  210. disabled={!parameterEnabled.max_tokens || disabled}
  211. />
  212. </div>
  213. {/* Seed */}
  214. <div className={`transition-opacity duration-200 mb-4 ${!parameterEnabled.seed || disabled ? 'opacity-50' : ''}`}>
  215. <div className="flex items-center justify-between mb-2">
  216. <div className="flex items-center gap-2">
  217. <Shuffle size={16} className="text-gray-500" />
  218. <Typography.Text strong className="text-sm">
  219. Seed
  220. </Typography.Text>
  221. <Typography.Text className="text-xs text-gray-400">
  222. (可选,用于复现结果)
  223. </Typography.Text>
  224. </div>
  225. <Button
  226. theme={parameterEnabled.seed ? 'solid' : 'borderless'}
  227. type={parameterEnabled.seed ? 'primary' : 'tertiary'}
  228. size="small"
  229. icon={parameterEnabled.seed ? <Check size={10} /> : <X size={10} />}
  230. onClick={() => onParameterToggle('seed')}
  231. className="!rounded-full !w-4 !h-4 !p-0 !min-w-0"
  232. disabled={disabled}
  233. />
  234. </div>
  235. <Input
  236. placeholder='随机种子 (留空为随机)'
  237. name='seed'
  238. autoComplete='new-password'
  239. value={inputs.seed || ''}
  240. onChange={(value) => onInputChange('seed', value === '' ? null : value)}
  241. className="!rounded-lg"
  242. disabled={!parameterEnabled.seed || disabled}
  243. />
  244. </div>
  245. </>
  246. );
  247. };
  248. export default ParameterControl;