ModelRatioSettings.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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. <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. <Row gutter={16}>
  201. <Col span={16}>
  202. <Form.Switch
  203. label={t('暴露倍率接口')}
  204. field={'ExposeRatioEnabled'}
  205. onChange={(value) =>
  206. setInputs({ ...inputs, ExposeRatioEnabled: value })
  207. }
  208. />
  209. </Col>
  210. </Row>
  211. </Form>
  212. <Space>
  213. <Button onClick={onSubmit}>{t('保存模型倍率设置')}</Button>
  214. <Popconfirm
  215. title={t('确定重置模型倍率吗?')}
  216. content={t('此修改将不可逆')}
  217. okType={'danger'}
  218. position={'top'}
  219. onConfirm={resetModelRatio}
  220. >
  221. <Button type={'danger'}>{t('重置模型倍率')}</Button>
  222. </Popconfirm>
  223. </Space>
  224. </Spin>
  225. );
  226. }