ModelRatioSettings.js 6.9 KB

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