mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
feat: refresh max token
This commit is contained in:
@@ -45,8 +45,8 @@ export const triggerModelCollection = (appId: string) =>
|
||||
POST<number>(`/app/share/collection?appId=${appId}`);
|
||||
|
||||
// ====================== data
|
||||
export const getTokenUsage = (data: { appId: string }) =>
|
||||
POST<{ tokenLen: number; date: Date }[]>(`/app/data/tokenUsage`, {
|
||||
export const getAppTotalUsage = (data: { appId: string }) =>
|
||||
POST<{ total: number; date: Date }[]>(`/app/data/totalUsage`, {
|
||||
...data,
|
||||
start: addDays(new Date(), -7),
|
||||
end: new Date()
|
||||
|
@@ -84,6 +84,7 @@ export const HistoryModule: AppModuleTemplateItemType = {
|
||||
]
|
||||
};
|
||||
|
||||
const defaultModel = chatModelList[0];
|
||||
export const ChatModule: AppModuleTemplateItemType = {
|
||||
logo: '/imgs/module/AI.png',
|
||||
name: 'AI 对话',
|
||||
@@ -94,9 +95,9 @@ export const ChatModule: AppModuleTemplateItemType = {
|
||||
inputs: [
|
||||
{
|
||||
key: 'model',
|
||||
type: FlowInputItemTypeEnum.select,
|
||||
type: FlowInputItemTypeEnum.custom,
|
||||
label: '对话模型',
|
||||
value: chatModelList[0]?.model,
|
||||
value: defaultModel?.model,
|
||||
list: chatModelList.map((item) => ({ label: item.name, value: item.model }))
|
||||
},
|
||||
{
|
||||
@@ -116,13 +117,16 @@ export const ChatModule: AppModuleTemplateItemType = {
|
||||
key: 'maxToken',
|
||||
type: FlowInputItemTypeEnum.slider,
|
||||
label: '回复上限',
|
||||
value: 3000,
|
||||
value: defaultModel ? defaultModel.contextMaxToken / 2 : 2000,
|
||||
min: 0,
|
||||
max: 4000,
|
||||
max: defaultModel?.contextMaxToken || 4000,
|
||||
step: 50,
|
||||
markList: [
|
||||
{ label: '0', value: 0 },
|
||||
{ label: '4000', value: 4000 }
|
||||
{
|
||||
label: `${defaultModel?.contextMaxToken || 4000}`,
|
||||
value: defaultModel?.contextMaxToken || 4000
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@@ -2,7 +2,6 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { jsonRes } from '@/service/response';
|
||||
import { connectToDatabase, Bill } from '@/service/mongo';
|
||||
import { authUser } from '@/service/utils/auth';
|
||||
import type { ChatHistoryItemType } from '@/types/chat';
|
||||
import { Types } from 'mongoose';
|
||||
|
||||
/* get one app chat history content number. */
|
||||
@@ -28,14 +27,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
month: { $month: '$time' },
|
||||
day: { $dayOfMonth: '$time' }
|
||||
},
|
||||
tokenLen: { $sum: '$tokenLen' } // 对tokenLen的值求和
|
||||
total: { $sum: '$total' }
|
||||
}
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
_id: 0,
|
||||
date: { $dateFromParts: { year: '$_id.year', month: '$_id.month', day: '$_id.day' } },
|
||||
tokenLen: 1
|
||||
total: 1
|
||||
}
|
||||
},
|
||||
{ $sort: { date: 1 } }
|
@@ -15,7 +15,7 @@ import { Types } from 'mongoose';
|
||||
import { moduleFetch } from '@/service/api/request';
|
||||
import { AppModuleItemType, RunningModuleItemType } from '@/types/app';
|
||||
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';
|
||||
|
||||
export type MessageItemType = ChatCompletionRequestMessage & { _id?: string };
|
||||
@@ -56,6 +56,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
variables = {}
|
||||
} = req.body as Props;
|
||||
|
||||
let billId = '';
|
||||
|
||||
try {
|
||||
if (!messages) {
|
||||
throw new Error('Prams Error');
|
||||
@@ -108,11 +110,11 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
res.setHeader('newHistoryId', String(newHistoryId));
|
||||
}
|
||||
|
||||
const billId = await createTaskBill({
|
||||
billId = await createTaskBill({
|
||||
userId,
|
||||
appName: app.name,
|
||||
appId,
|
||||
source: BillSourceEnum.fastgpt
|
||||
source: authType === 'apikey' ? BillSourceEnum.api : BillSourceEnum.fastgpt
|
||||
});
|
||||
|
||||
/* start process */
|
||||
@@ -125,7 +127,7 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
userChatInput: prompt.value
|
||||
},
|
||||
stream,
|
||||
billId: ''
|
||||
billId
|
||||
});
|
||||
|
||||
// save chat
|
||||
@@ -184,6 +186,8 @@ export default withNextCors(async function handler(req: NextApiRequest, res: Nex
|
||||
billId
|
||||
});
|
||||
} catch (err: any) {
|
||||
delTaskBill(billId);
|
||||
|
||||
if (stream) {
|
||||
res.status(500);
|
||||
sseErrRes(res, err);
|
||||
|
@@ -1,9 +1,10 @@
|
||||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import * as echarts from 'echarts';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { getTokenUsage } from '@/api/app';
|
||||
import { getAppTotalUsage } from '@/api/app';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import dayjs from 'dayjs';
|
||||
import { formatPrice } from '@/utils/user';
|
||||
|
||||
const map = {
|
||||
blue: {
|
||||
@@ -98,7 +99,7 @@ const TokenUsage = ({ appId }: { appId: string }) => {
|
||||
|
||||
const Dom = useRef<HTMLDivElement>(null);
|
||||
const myChart = useRef<echarts.ECharts>();
|
||||
const { data = [] } = useQuery(['init'], () => getTokenUsage({ appId }));
|
||||
const { data = [] } = useQuery(['init'], () => getAppTotalUsage({ appId }));
|
||||
|
||||
const option = useMemo(
|
||||
() => ({
|
||||
@@ -110,7 +111,7 @@ const TokenUsage = ({ appId }: { appId: string }) => {
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
max: Math.max(...data.map((item) => item.tokenLen)),
|
||||
max: Math.max(...data.map((item) => item.total)),
|
||||
min: 0
|
||||
},
|
||||
grid: {
|
||||
@@ -132,14 +133,14 @@ const TokenUsage = ({ appId }: { appId: string }) => {
|
||||
return `
|
||||
<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>
|
||||
`;
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: data.map((item) => item.tokenLen),
|
||||
data: data.map((item) => item.total),
|
||||
type: 'line',
|
||||
showSymbol: true,
|
||||
animationDuration: 300,
|
||||
@@ -170,7 +171,7 @@ const TokenUsage = ({ appId }: { appId: string }) => {
|
||||
if (!Dom.current || myChart?.current?.getOption()) return;
|
||||
myChart.current = echarts.init(Dom.current);
|
||||
myChart.current && myChart.current.setOption(option);
|
||||
}, [Dom]);
|
||||
}, []);
|
||||
|
||||
// data changed, update
|
||||
useEffect(() => {
|
@@ -14,8 +14,8 @@ import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@/components/Icon';
|
||||
|
||||
const InfoModal = dynamic(() => import('./InfoModal'));
|
||||
const TokenUsage = dynamic(() => import('./Charts/TokenUsage'));
|
||||
const AppEdit = dynamic(() => import('./edit'));
|
||||
const TotalUsage = dynamic(() => import('./Charts/TotalUsage'), { ssr: false });
|
||||
const AppEdit = dynamic(() => import('./edit'), { ssr: false });
|
||||
import styles from '../../list/index.module.scss';
|
||||
|
||||
const Settings = ({ appId }: { appId: string }) => {
|
||||
@@ -143,10 +143,10 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
</Box>
|
||||
<Box>
|
||||
<Box mb={2} fontSize={['md', 'xl']}>
|
||||
近 7 日 Tokens 消耗
|
||||
近 7 日消费
|
||||
</Box>
|
||||
<Box h={'150px'}>
|
||||
<TokenUsage appId={appId} />
|
||||
<Box h={'150px'} w={'100%'}>
|
||||
<TotalUsage appId={appId} />
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
|
@@ -7,6 +7,8 @@ import Container from './modules/Container';
|
||||
import RenderInput from './render/RenderInput';
|
||||
import RenderOutput from './render/RenderOutput';
|
||||
import { FlowOutputItemTypeEnum } from '@/constants/flow';
|
||||
import MySelect from '@/components/Select';
|
||||
import { chatModelList } from '@/store/static';
|
||||
|
||||
const NodeChat = ({
|
||||
data: { moduleId, inputs, outputs, onChangeNode, ...props }
|
||||
@@ -15,11 +17,57 @@ const NodeChat = ({
|
||||
() => outputs.filter((item) => item.type !== FlowOutputItemTypeEnum.hidden).length,
|
||||
[outputs]
|
||||
);
|
||||
|
||||
return (
|
||||
<NodeCard minW={'400px'} logo={'/icon/logo.png'} name={'对话'} moduleId={moduleId} {...props}>
|
||||
<NodeCard minW={'400px'} moduleId={moduleId} {...props}>
|
||||
<Divider text="Input" />
|
||||
<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>
|
||||
{outputsLen > 0 && (
|
||||
<>
|
||||
|
Reference in New Issue
Block a user