import React, { useContext, useEffect, useRef, useMemo, useState } from 'react'; import { API, copy, showError, showSuccess } from '../helpers'; import { Banner, Input, Layout, Modal, Space, Table, Tag, Tooltip, Popover, ImagePreview, Button, } from '@douyinfe/semi-ui'; import { IconMore, IconVerify, IconUploadError, IconHelpCircle, } from '@douyinfe/semi-icons'; import { UserContext } from '../context/User/index.js'; import Text from '@douyinfe/semi-ui/lib/es/typography/text'; function renderQuotaType(type) { // Ensure all cases are string literals by adding quotes. switch (type) { case 1: return ( 按次计费 ); case 0: return ( 按量计费 ); default: return '未知'; } } function renderAvailable(available) { return available ? ( 您的分组可以使用该模型 } position='top' key={available} style={{ backgroundColor: 'rgba(var(--semi-blue-4),1)', borderColor: 'rgba(var(--semi-blue-4),1)', color: 'var(--semi-color-white)', borderWidth: 1, borderStyle: 'solid', }} > ) : ( 您的分组无权使用该模型 } position='top' key={available} style={{ backgroundColor: 'rgba(var(--semi-blue-4),1)', borderColor: 'rgba(var(--semi-blue-4),1)', color: 'var(--semi-color-white)', borderWidth: 1, borderStyle: 'solid', }} > ); } const ModelPricing = () => { const [filteredValue, setFilteredValue] = useState([]); const compositionRef = useRef({ isComposition: false }); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [modalImageUrl, setModalImageUrl] = useState(''); const [isModalOpenurl, setIsModalOpenurl] = useState(false); const rowSelection = useMemo( () => ({ onChange: (selectedRowKeys, selectedRows) => { setSelectedRowKeys(selectedRowKeys); }, getCheckboxProps: record => ({ disabled: record.name === 'Michael James', // Column configuration not to be checked name: record.model_name, }), }), [] ); const handleChange = (value) => { if (compositionRef.current.isComposition) { return; } const newFilteredValue = value ? [value] : []; setFilteredValue(newFilteredValue); }; const handleCompositionStart = () => { compositionRef.current.isComposition = true; }; const handleCompositionEnd = (event) => { compositionRef.current.isComposition = false; const value = event.target.value; const newFilteredValue = value ? [value] : []; setFilteredValue(newFilteredValue); }; const columns = [ { title: '可用性', dataIndex: 'available', render: (text, record, index) => { return renderAvailable(text); }, sorter: (a, b) => a.available - b.available, }, { title: ( 模型名称 ), dataIndex: 'model_name', // 以finish_time作为dataIndex render: (text, record, index) => { return ( <> { copyText(text); }} > {text} ); }, onFilter: (value, record) => record.model_name.includes(value), filteredValue, }, { title: '计费类型', dataIndex: 'quota_type', render: (text, record, index) => { return renderQuotaType(parseInt(text)); }, sorter: (a, b) => a.quota_type - b.quota_type, }, { title: () => ( 倍率 倍率是为了方便换算不同价格的模型
点击查看倍率说明 } position='top' style={{ backgroundColor: 'rgba(var(--semi-blue-4),1)', borderColor: 'rgba(var(--semi-blue-4),1)', color: 'var(--semi-color-white)', borderWidth: 1, borderStyle: 'solid', }} > { setModalImageUrl('/ratio.png'); setIsModalOpenurl(true); }} />
), dataIndex: 'model_ratio', render: (text, record, index) => { let content = text; let completionRatio = parseFloat(record.completion_ratio.toFixed(3)); content = ( <> 模型:{record.quota_type === 0 ? text : '无'}
补全:{record.quota_type === 0 ? completionRatio : '无'} ); return
{content}
; }, }, { title: '模型价格', dataIndex: 'model_price', render: (text, record, index) => { let content = text; if (record.quota_type === 0) { let inputRatioPrice = record.model_ratio * 2.0 * record.group_ratio; let completionRatioPrice = record.model_ratio * record.completion_ratio * 2.0 * record.group_ratio; content = ( <> 提示 ${inputRatioPrice} / 1M tokens
补全 ${completionRatioPrice} / 1M tokens ); } else { let price = parseFloat(text) * record.group_ratio; content = <>模型价格:${price}; } return
{content}
; }, }, ]; const [models, setModels] = useState([]); const [loading, setLoading] = useState(true); const [userState, userDispatch] = useContext(UserContext); const [groupRatio, setGroupRatio] = useState(1); const setModelsFormat = (models, groupRatio) => { for (let i = 0; i < models.length; i++) { models[i].key = models[i].model_name; models[i].group_ratio = groupRatio; } // sort by quota_type models.sort((a, b) => { return a.quota_type - b.quota_type; }); // sort by model_name, start with gpt is max, other use localeCompare models.sort((a, b) => { if (a.model_name.startsWith('gpt') && !b.model_name.startsWith('gpt')) { return -1; } else if ( !a.model_name.startsWith('gpt') && b.model_name.startsWith('gpt') ) { return 1; } else { return a.model_name.localeCompare(b.model_name); } }); setModels(models); }; const loadPricing = async () => { setLoading(true); let url = ''; url = `/api/pricing`; const res = await API.get(url); const { success, message, data, group_ratio } = res.data; if (success) { setGroupRatio(group_ratio); setModelsFormat(data, group_ratio); } else { showError(message); } setLoading(false); }; const refresh = async () => { await loadPricing(); }; const copyText = async (text) => { if (await copy(text)) { showSuccess('已复制:' + text); } else { // setSearchKeyword(text); Modal.error({ title: '无法复制到剪贴板,请手动复制', content: text }); } }; useEffect(() => { refresh().then(); }, []); return ( <> {userState.user ? ( ) : ( )}
按量计费费用 = 分组倍率 × 模型倍率 × (提示token数 + 补全token数 × 补全倍率)/ 500000 (单位:美元)} closeIcon="null" />
setIsModalOpenurl(visible)} /> ); }; export default ModelPricing;