ModelRatioSettings.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import React, { useEffect, useState, useRef } from 'react';
  2. import {
  3. Button,
  4. Col,
  5. Form,
  6. Popconfirm,
  7. Row,
  8. Space,
  9. Spin,
  10. } from '@douyinfe/semi-ui';
  11. import {
  12. compareObjects,
  13. API,
  14. showError,
  15. showSuccess,
  16. showWarning,
  17. verifyJSON,
  18. } from '../../../helpers';
  19. import { useTranslation } from 'react-i18next';
  20. export default function ModelRatioSettings(props) {
  21. const [loading, setLoading] = useState(false);
  22. const [inputs, setInputs] = useState({
  23. ModelPrice: '',
  24. ModelRatio: '',
  25. CacheRatio: '',
  26. CompletionRatio: '',
  27. ExposeRatioEnabled: false,
  28. });
  29. const refForm = useRef();
  30. const [inputsRow, setInputsRow] = useState(inputs);
  31. const { t } = useTranslation();
  32. async function onSubmit() {
  33. try {
  34. await refForm.current
  35. .validate()
  36. .then(() => {
  37. const updateArray = compareObjects(inputs, inputsRow);
  38. if (!updateArray.length)
  39. return showWarning(t('你似乎并没有修改什么'));
  40. const requestQueue = updateArray.map((item) => {
  41. const value =
  42. typeof inputs[item.key] === 'boolean'
  43. ? String(inputs[item.key])
  44. : inputs[item.key];
  45. return API.put('/api/option/', { key: item.key, value });
  46. });
  47. setLoading(true);
  48. Promise.all(requestQueue)
  49. .then((res) => {
  50. if (res.includes(undefined)) {
  51. return showError(
  52. requestQueue.length > 1
  53. ? t('部分保存失败,请重试')
  54. : t('保存失败'),
  55. );
  56. }
  57. for (let i = 0; i < res.length; i++) {
  58. if (!res[i].data.success) {
  59. return showError(res[i].data.message);
  60. }
  61. }
  62. showSuccess(t('保存成功'));
  63. props.refresh();
  64. })
  65. .catch((error) => {
  66. console.error('Unexpected error:', error);
  67. showError(t('保存失败,请重试'));
  68. })
  69. .finally(() => {
  70. setLoading(false);
  71. });
  72. })
  73. .catch(() => {
  74. showError(t('请检查输入'));
  75. });
  76. } catch (error) {
  77. showError(t('请检查输入'));
  78. console.error(error);
  79. }
  80. }
  81. async function resetModelRatio() {
  82. try {
  83. let res = await API.post(`/api/option/rest_model_ratio`);
  84. if (res.data.success) {
  85. showSuccess(res.data.message);
  86. props.refresh();
  87. } else {
  88. showError(res.data.message);
  89. }
  90. } catch (error) {
  91. showError(error);
  92. }
  93. }
  94. useEffect(() => {
  95. const currentInputs = {};
  96. for (let key in props.options) {
  97. if (Object.keys(inputs).includes(key)) {
  98. currentInputs[key] = props.options[key];
  99. }
  100. }
  101. setInputs(currentInputs);
  102. setInputsRow(structuredClone(currentInputs));
  103. refForm.current.setValues(currentInputs);
  104. }, [props.options]);
  105. return (
  106. <Spin spinning={loading}>
  107. <Form
  108. values={inputs}
  109. getFormApi={(formAPI) => (refForm.current = formAPI)}
  110. style={{ marginBottom: 15 }}
  111. >
  112. <Form.Section>
  113. <Row gutter={16}>
  114. <Col xs={24} sm={16}>
  115. <Form.TextArea
  116. label={t('模型固定价格')}
  117. extraText={t('一次调用消耗多少刀,优先级大于模型倍率')}
  118. placeholder={t(
  119. '为一个 JSON 文本,键为模型名称,值为一次调用消耗多少刀,比如 "gpt-4-gizmo-*": 0.1,一次消耗0.1刀',
  120. )}
  121. field={'ModelPrice'}
  122. autosize={{ minRows: 6, maxRows: 12 }}
  123. trigger='blur'
  124. stopValidateWithError
  125. rules={[
  126. {
  127. validator: (rule, value) => verifyJSON(value),
  128. message: '不是合法的 JSON 字符串',
  129. },
  130. ]}
  131. onChange={(value) =>
  132. setInputs({ ...inputs, ModelPrice: value })
  133. }
  134. />
  135. </Col>
  136. </Row>
  137. <Row gutter={16}>
  138. <Col xs={24} sm={16}>
  139. <Form.TextArea
  140. label={t('模型倍率')}
  141. placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率')}
  142. field={'ModelRatio'}
  143. autosize={{ minRows: 6, maxRows: 12 }}
  144. trigger='blur'
  145. stopValidateWithError
  146. rules={[
  147. {
  148. validator: (rule, value) => verifyJSON(value),
  149. message: '不是合法的 JSON 字符串',
  150. },
  151. ]}
  152. onChange={(value) =>
  153. setInputs({ ...inputs, ModelRatio: value })
  154. }
  155. />
  156. </Col>
  157. </Row>
  158. <Row gutter={16}>
  159. <Col xs={24} sm={16}>
  160. <Form.TextArea
  161. label={t('提示缓存倍率')}
  162. placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率')}
  163. field={'CacheRatio'}
  164. autosize={{ minRows: 6, maxRows: 12 }}
  165. trigger='blur'
  166. stopValidateWithError
  167. rules={[
  168. {
  169. validator: (rule, value) => verifyJSON(value),
  170. message: '不是合法的 JSON 字符串',
  171. },
  172. ]}
  173. onChange={(value) =>
  174. setInputs({ ...inputs, CacheRatio: value })
  175. }
  176. />
  177. </Col>
  178. </Row>
  179. <Row gutter={16}>
  180. <Col xs={24} sm={16}>
  181. <Form.TextArea
  182. label={t('模型补全倍率(仅对自定义模型有效)')}
  183. extraText={t('仅对自定义模型有效')}
  184. placeholder={t('为一个 JSON 文本,键为模型名称,值为倍率')}
  185. field={'CompletionRatio'}
  186. autosize={{ minRows: 6, maxRows: 12 }}
  187. trigger='blur'
  188. stopValidateWithError
  189. rules={[
  190. {
  191. validator: (rule, value) => verifyJSON(value),
  192. message: '不是合法的 JSON 字符串',
  193. },
  194. ]}
  195. onChange={(value) =>
  196. setInputs({ ...inputs, CompletionRatio: value })
  197. }
  198. />
  199. </Col>
  200. </Row>
  201. <Row gutter={16}>
  202. <Col span={16}>
  203. <Form.Switch
  204. label={t('暴露倍率接口')}
  205. field={'ExposeRatioEnabled'}
  206. onChange={(value) =>
  207. setInputs({ ...inputs, ExposeRatioEnabled: value })
  208. }
  209. />
  210. </Col>
  211. </Row>
  212. </Form.Section>
  213. </Form>
  214. <Space>
  215. <Button onClick={onSubmit}>{t('保存模型倍率设置')}</Button>
  216. <Popconfirm
  217. title={t('确定重置模型倍率吗?')}
  218. content={t('此修改将不可逆')}
  219. okType={'danger'}
  220. position={'top'}
  221. onConfirm={resetModelRatio}
  222. >
  223. <Button type={'danger'}>{t('重置模型倍率')}</Button>
  224. </Popconfirm>
  225. </Space>
  226. </Spin>
  227. );
  228. }