ModelPricing.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import React, { useContext, useEffect, useState } from 'react';
  2. import { API, copy, showError, showSuccess } from '../helpers';
  3. import { Banner, Layout, Modal, Table, Tag, Tooltip } from '@douyinfe/semi-ui';
  4. import { stringToColor } from '../helpers/render.js';
  5. import { UserContext } from '../context/User/index.js';
  6. import Text from '@douyinfe/semi-ui/lib/es/typography/text';
  7. function renderQuotaType(type) {
  8. // Ensure all cases are string literals by adding quotes.
  9. switch (type) {
  10. case 1:
  11. return (
  12. <Tag color='green' size='large'>
  13. 按次计费
  14. </Tag>
  15. );
  16. case 0:
  17. return (
  18. <Tag color='blue' size='large'>
  19. 按量计费
  20. </Tag>
  21. );
  22. default:
  23. return (
  24. <Tag color='white' size='large'>
  25. 未知
  26. </Tag>
  27. );
  28. }
  29. }
  30. function renderAvailable(available) {
  31. return available ? (
  32. <Tag color='green' size='large'>
  33. 可用
  34. </Tag>
  35. ) : (
  36. <Tooltip content='您所在的分组不可用'>
  37. <Tag color='red' size='large'>
  38. 不可用
  39. </Tag>
  40. </Tooltip>
  41. );
  42. }
  43. const ModelPricing = () => {
  44. const columns = [
  45. {
  46. title: '可用性',
  47. dataIndex: 'available',
  48. render: (text, record, index) => {
  49. return renderAvailable(text);
  50. },
  51. },
  52. {
  53. title: '提供者',
  54. dataIndex: 'owner_by',
  55. render: (text, record, index) => {
  56. return (
  57. <>
  58. <Tag color={stringToColor(text)} size='large'>
  59. {text}
  60. </Tag>
  61. </>
  62. );
  63. },
  64. },
  65. {
  66. title: '模型名称',
  67. dataIndex: 'model_name', // 以finish_time作为dataIndex
  68. render: (text, record, index) => {
  69. return (
  70. <>
  71. <Tag
  72. color={stringToColor(record.owner_by)}
  73. size='large'
  74. onClick={() => {
  75. copyText(text);
  76. }}
  77. >
  78. {text}
  79. </Tag>
  80. </>
  81. );
  82. },
  83. },
  84. {
  85. title: '计费类型',
  86. dataIndex: 'quota_type',
  87. render: (text, record, index) => {
  88. return renderQuotaType(parseInt(text));
  89. },
  90. },
  91. {
  92. title: '模型倍率',
  93. dataIndex: 'model_ratio',
  94. render: (text, record, index) => {
  95. return <div>{record.quota_type === 0 ? text : 'N/A'}</div>;
  96. },
  97. },
  98. {
  99. title: '补全倍率',
  100. dataIndex: 'completion_ratio',
  101. render: (text, record, index) => {
  102. let ratio = parseFloat(text.toFixed(3));
  103. return <div>{record.quota_type === 0 ? ratio : 'N/A'}</div>;
  104. },
  105. },
  106. {
  107. title: '模型价格',
  108. dataIndex: 'model_price',
  109. render: (text, record, index) => {
  110. let content = text;
  111. if (record.quota_type === 0) {
  112. let inputRatioPrice = record.model_ratio * 2.0 * record.group_ratio;
  113. let completionRatioPrice =
  114. record.model_ratio *
  115. record.completion_ratio *
  116. 2.0 *
  117. record.group_ratio;
  118. content = (
  119. <>
  120. <Text>提示 ${inputRatioPrice} / 1M tokens</Text>
  121. <br />
  122. <Text>补全 ${completionRatioPrice} / 1M tokens</Text>
  123. </>
  124. );
  125. } else {
  126. let price = parseFloat(text) * record.group_ratio;
  127. content = <>模型价格:${price}</>;
  128. }
  129. return <div>{content}</div>;
  130. },
  131. },
  132. ];
  133. const [models, setModels] = useState([]);
  134. const [loading, setLoading] = useState(true);
  135. const [userState, userDispatch] = useContext(UserContext);
  136. const [groupRatio, setGroupRatio] = useState(1);
  137. const setModelsFormat = (models, groupRatio) => {
  138. for (let i = 0; i < models.length; i++) {
  139. models[i].key = i;
  140. models[i].group_ratio = groupRatio;
  141. }
  142. // sort by quota_type
  143. models.sort((a, b) => {
  144. return a.quota_type - b.quota_type;
  145. });
  146. // sort by owner_by, openai is max, other use localeCompare
  147. models.sort((a, b) => {
  148. if (a.owner_by === 'openai') {
  149. return -1;
  150. } else if (b.owner_by === 'openai') {
  151. return 1;
  152. } else {
  153. return a.owner_by.localeCompare(b.owner_by);
  154. }
  155. });
  156. setModels(models);
  157. };
  158. const loadPricing = async () => {
  159. setLoading(true);
  160. let url = '';
  161. url = `/api/pricing`;
  162. const res = await API.get(url);
  163. const { success, message, data, group_ratio } = res.data;
  164. if (success) {
  165. setGroupRatio(group_ratio);
  166. setModelsFormat(data, group_ratio);
  167. } else {
  168. showError(message);
  169. }
  170. setLoading(false);
  171. };
  172. const refresh = async () => {
  173. await loadPricing();
  174. };
  175. const copyText = async (text) => {
  176. if (await copy(text)) {
  177. showSuccess('已复制:' + text);
  178. } else {
  179. // setSearchKeyword(text);
  180. Modal.error({ title: '无法复制到剪贴板,请手动复制', content: text });
  181. }
  182. };
  183. useEffect(() => {
  184. refresh().then();
  185. }, []);
  186. return (
  187. <>
  188. <Layout>
  189. {userState.user ? (
  190. <Banner
  191. type='info'
  192. description={`您的分组为:${userState.user.group},分组倍率为:${groupRatio}`}
  193. />
  194. ) : (
  195. <Banner
  196. type='warning'
  197. description={`您还未登陆,显示的价格为默认分组倍率: ${groupRatio}`}
  198. />
  199. )}
  200. <Table
  201. style={{ marginTop: 5 }}
  202. columns={columns}
  203. dataSource={models}
  204. loading={loading}
  205. pagination={{
  206. pageSize: models.length,
  207. showSizeChanger: false,
  208. }}
  209. />
  210. </Layout>
  211. </>
  212. );
  213. };
  214. export default ModelPricing;