feat: refresh max token

This commit is contained in:
archer
2023-07-14 10:05:29 +08:00
parent f3715731c4
commit 358c4716f9
7 changed files with 83 additions and 27 deletions

View File

@@ -45,8 +45,8 @@ export const triggerModelCollection = (appId: string) =>
POST<number>(`/app/share/collection?appId=${appId}`); POST<number>(`/app/share/collection?appId=${appId}`);
// ====================== data // ====================== data
export const getTokenUsage = (data: { appId: string }) => export const getAppTotalUsage = (data: { appId: string }) =>
POST<{ tokenLen: number; date: Date }[]>(`/app/data/tokenUsage`, { POST<{ total: number; date: Date }[]>(`/app/data/totalUsage`, {
...data, ...data,
start: addDays(new Date(), -7), start: addDays(new Date(), -7),
end: new Date() end: new Date()

View File

@@ -84,6 +84,7 @@ export const HistoryModule: AppModuleTemplateItemType = {
] ]
}; };
const defaultModel = chatModelList[0];
export const ChatModule: AppModuleTemplateItemType = { export const ChatModule: AppModuleTemplateItemType = {
logo: '/imgs/module/AI.png', logo: '/imgs/module/AI.png',
name: 'AI 对话', name: 'AI 对话',
@@ -94,9 +95,9 @@ export const ChatModule: AppModuleTemplateItemType = {
inputs: [ inputs: [
{ {
key: 'model', key: 'model',
type: FlowInputItemTypeEnum.select, type: FlowInputItemTypeEnum.custom,
label: '对话模型', label: '对话模型',
value: chatModelList[0]?.model, value: defaultModel?.model,
list: chatModelList.map((item) => ({ label: item.name, value: item.model })) list: chatModelList.map((item) => ({ label: item.name, value: item.model }))
}, },
{ {
@@ -116,13 +117,16 @@ export const ChatModule: AppModuleTemplateItemType = {
key: 'maxToken', key: 'maxToken',
type: FlowInputItemTypeEnum.slider, type: FlowInputItemTypeEnum.slider,
label: '回复上限', label: '回复上限',
value: 3000, value: defaultModel ? defaultModel.contextMaxToken / 2 : 2000,
min: 0, min: 0,
max: 4000, max: defaultModel?.contextMaxToken || 4000,
step: 50, step: 50,
markList: [ markList: [
{ label: '0', value: 0 }, { label: '0', value: 0 },
{ label: '4000', value: 4000 } {
label: `${defaultModel?.contextMaxToken || 4000}`,
value: defaultModel?.contextMaxToken || 4000
}
] ]
}, },
{ {

View File

@@ -2,7 +2,6 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { connectToDatabase, Bill } from '@/service/mongo'; import { connectToDatabase, Bill } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import type { ChatHistoryItemType } from '@/types/chat';
import { Types } from 'mongoose'; import { Types } from 'mongoose';
/* get one app chat history content number. */ /* get one app chat history content number. */
@@ -28,14 +27,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
month: { $month: '$time' }, month: { $month: '$time' },
day: { $dayOfMonth: '$time' } day: { $dayOfMonth: '$time' }
}, },
tokenLen: { $sum: '$tokenLen' } // 对tokenLen的值求和 total: { $sum: '$total' }
} }
}, },
{ {
$project: { $project: {
_id: 0, _id: 0,
date: { $dateFromParts: { year: '$_id.year', month: '$_id.month', day: '$_id.day' } }, date: { $dateFromParts: { year: '$_id.year', month: '$_id.month', day: '$_id.day' } },
tokenLen: 1 total: 1
} }
}, },
{ $sort: { date: 1 } } { $sort: { date: 1 } }

View File

@@ -15,7 +15,7 @@ import { Types } from 'mongoose';
import { moduleFetch } from '@/service/api/request'; import { moduleFetch } from '@/service/api/request';
import { AppModuleItemType, RunningModuleItemType } from '@/types/app'; import { AppModuleItemType, RunningModuleItemType } from '@/types/app';
import { FlowInputItemTypeEnum } from '@/constants/flow'; import { FlowInputItemTypeEnum } from '@/constants/flow';
import { finishTaskBill, createTaskBill } from '@/service/events/pushBill'; import { finishTaskBill, createTaskBill, delTaskBill } from '@/service/events/pushBill';
import { BillSourceEnum } from '@/constants/user'; import { BillSourceEnum } from '@/constants/user';
export type MessageItemType = ChatCompletionRequestMessage & { _id?: string }; export type MessageItemType = ChatCompletionRequestMessage & { _id?: string };
@@ -56,6 +56,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
variables = {} variables = {}
} = req.body as Props; } = req.body as Props;
let billId = '';
try { try {
if (!messages) { if (!messages) {
throw new Error('Prams Error'); throw new Error('Prams Error');
@@ -108,11 +110,11 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
res.setHeader('newHistoryId', String(newHistoryId)); res.setHeader('newHistoryId', String(newHistoryId));
} }
const billId = await createTaskBill({ billId = await createTaskBill({
userId, userId,
appName: app.name, appName: app.name,
appId, appId,
source: BillSourceEnum.fastgpt source: authType === 'apikey' ? BillSourceEnum.api : BillSourceEnum.fastgpt
}); });
/* start process */ /* start process */
@@ -125,7 +127,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
userChatInput: prompt.value userChatInput: prompt.value
}, },
stream, stream,
billId: '' billId
}); });
// save chat // save chat
@@ -184,6 +186,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
billId billId
}); });
} catch (err: any) { } catch (err: any) {
delTaskBill(billId);
if (stream) { if (stream) {
res.status(500); res.status(500);
sseErrRes(res, err); sseErrRes(res, err);

View File

@@ -1,9 +1,10 @@
import React, { useEffect, useMemo, useRef } from 'react'; import React, { useEffect, useMemo, useRef } from 'react';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { getTokenUsage } from '@/api/app'; import { getAppTotalUsage } from '@/api/app';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { formatPrice } from '@/utils/user';
const map = { const map = {
blue: { blue: {
@@ -98,7 +99,7 @@ const TokenUsage = ({ appId }: { appId: string }) => {
const Dom = useRef<HTMLDivElement>(null); const Dom = useRef<HTMLDivElement>(null);
const myChart = useRef<echarts.ECharts>(); const myChart = useRef<echarts.ECharts>();
const { data = [] } = useQuery(['init'], () => getTokenUsage({ appId })); const { data = [] } = useQuery(['init'], () => getAppTotalUsage({ appId }));
const option = useMemo( const option = useMemo(
() => ({ () => ({
@@ -110,7 +111,7 @@ const TokenUsage = ({ appId }: { appId: string }) => {
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
max: Math.max(...data.map((item) => item.tokenLen)), max: Math.max(...data.map((item) => item.total)),
min: 0 min: 0
}, },
grid: { grid: {
@@ -132,14 +133,14 @@ const TokenUsage = ({ appId }: { appId: string }) => {
return ` return `
<div> <div>
<div>${dayjs(data.axisValue).format('YYYY/MM/DD')}</div> <div>${dayjs(data.axisValue).format('YYYY/MM/DD')}</div>
<div>${((e[0]?.value || 0) / 1000).toFixed(2)}k Tokens</div> <div>${formatPrice(e[0]?.value || 0)}</div>
</div> </div>
`; `;
} }
}, },
series: [ series: [
{ {
data: data.map((item) => item.tokenLen), data: data.map((item) => item.total),
type: 'line', type: 'line',
showSymbol: true, showSymbol: true,
animationDuration: 300, animationDuration: 300,
@@ -170,7 +171,7 @@ const TokenUsage = ({ appId }: { appId: string }) => {
if (!Dom.current || myChart?.current?.getOption()) return; if (!Dom.current || myChart?.current?.getOption()) return;
myChart.current = echarts.init(Dom.current); myChart.current = echarts.init(Dom.current);
myChart.current && myChart.current.setOption(option); myChart.current && myChart.current.setOption(option);
}, [Dom]); }, []);
// data changed, update // data changed, update
useEffect(() => { useEffect(() => {

View File

@@ -14,8 +14,8 @@ import Avatar from '@/components/Avatar';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
const InfoModal = dynamic(() => import('./InfoModal')); const InfoModal = dynamic(() => import('./InfoModal'));
const TokenUsage = dynamic(() => import('./Charts/TokenUsage')); const TotalUsage = dynamic(() => import('./Charts/TotalUsage'), { ssr: false });
const AppEdit = dynamic(() => import('./edit')); const AppEdit = dynamic(() => import('./edit'), { ssr: false });
import styles from '../../list/index.module.scss'; import styles from '../../list/index.module.scss';
const Settings = ({ appId }: { appId: string }) => { const Settings = ({ appId }: { appId: string }) => {
@@ -143,10 +143,10 @@ const Settings = ({ appId }: { appId: string }) => {
</Box> </Box>
<Box> <Box>
<Box mb={2} fontSize={['md', 'xl']}> <Box mb={2} fontSize={['md', 'xl']}>
7 Tokens 7
</Box> </Box>
<Box h={'150px'}> <Box h={'150px'} w={'100%'}>
<TokenUsage appId={appId} /> <TotalUsage appId={appId} />
</Box> </Box>
</Box> </Box>
</Grid> </Grid>

View File

@@ -7,6 +7,8 @@ import Container from './modules/Container';
import RenderInput from './render/RenderInput'; import RenderInput from './render/RenderInput';
import RenderOutput from './render/RenderOutput'; import RenderOutput from './render/RenderOutput';
import { FlowOutputItemTypeEnum } from '@/constants/flow'; import { FlowOutputItemTypeEnum } from '@/constants/flow';
import MySelect from '@/components/Select';
import { chatModelList } from '@/store/static';
const NodeChat = ({ const NodeChat = ({
data: { moduleId, inputs, outputs, onChangeNode, ...props } data: { moduleId, inputs, outputs, onChangeNode, ...props }
@@ -15,11 +17,57 @@ const NodeChat = ({
() => outputs.filter((item) => item.type !== FlowOutputItemTypeEnum.hidden).length, () => outputs.filter((item) => item.type !== FlowOutputItemTypeEnum.hidden).length,
[outputs] [outputs]
); );
return ( return (
<NodeCard minW={'400px'} logo={'/icon/logo.png'} name={'对话'} moduleId={moduleId} {...props}> <NodeCard minW={'400px'} moduleId={moduleId} {...props}>
<Divider text="Input" /> <Divider text="Input" />
<Container> <Container>
<RenderInput moduleId={moduleId} onChangeNode={onChangeNode} flowInputList={inputs} /> <RenderInput
moduleId={moduleId}
onChangeNode={onChangeNode}
flowInputList={inputs}
CustomComponent={{
model: (inputItem) => (
<MySelect
width={'100%'}
value={inputItem.value}
list={inputItem.list || []}
onchange={(e) => {
onChangeNode({
moduleId,
key: inputItem.key,
value: e
});
// update max tokens
const model = chatModelList.find((item) => item.model === e);
if (!model) return;
onChangeNode({
moduleId,
key: 'maxToken',
valueKey: 'markList',
value: [
{ label: '0', value: 0 },
{ label: `${model.contextMaxToken}`, value: model.contextMaxToken }
]
});
onChangeNode({
moduleId,
key: 'maxToken',
valueKey: 'max',
value: model.contextMaxToken
});
onChangeNode({
moduleId,
key: 'maxToken',
valueKey: 'value',
value: model.contextMaxToken / 2
});
}}
/>
)
}}
/>
</Container> </Container>
{outputsLen > 0 && ( {outputsLen > 0 && (
<> <>