From 1293f71bcef45ad35e4aa3177db2bbb4764b0ac2 Mon Sep 17 00:00:00 2001 From: jialin Date: Wed, 26 Jun 2024 18:05:30 +0800 Subject: [PATCH] chore: dashboard api --- src/components/charts/column-bar.tsx | 53 ++++++--- src/components/charts/h-bar.tsx | 50 ++++++-- src/components/charts/line-chart.tsx | 13 ++- src/components/charts/liquid.tsx | 2 +- src/global.less | 13 +++ src/pages/dashboard/apis/index.ts | 7 ++ .../dashboard/components/active-table.tsx | 73 ++++-------- src/pages/dashboard/components/over-view.tsx | 25 +--- .../components/resource-utilization.tsx | 110 +++++++++--------- .../dashboard/components/system-load.tsx | 18 ++- src/pages/dashboard/components/usage.tsx | 97 ++++++++++++++- .../dashboard/config/dashboard-context.ts | 8 ++ src/pages/dashboard/config/index.ts | 8 +- src/pages/dashboard/config/types.ts | 62 ++++++++++ src/pages/dashboard/index.tsx | 36 +++++- src/pages/llmodels/components/add-modal.tsx | 2 +- src/pages/llmodels/index.tsx | 2 +- .../playground/components/chat-footer.tsx | 17 ++- .../playground/components/ground-left.tsx | 1 + src/pages/playground/style/ground-left.less | 4 + src/pages/resources/components/workers.tsx | 17 +-- 21 files changed, 430 insertions(+), 188 deletions(-) create mode 100644 src/pages/dashboard/config/dashboard-context.ts create mode 100644 src/pages/dashboard/config/types.ts diff --git a/src/components/charts/column-bar.tsx b/src/components/charts/column-bar.tsx index 42c6d588..d9200054 100644 --- a/src/components/charts/column-bar.tsx +++ b/src/components/charts/column-bar.tsx @@ -6,38 +6,60 @@ interface BarChartProps { yField: string; title?: string; height?: number; + group?: boolean; + colorField?: string; + seriesField?: string; + stack?: boolean; + legend?: any; } const BarChart: React.FC = (props) => { - const { data, xField, yField, title, height = 260 } = props; + const { + data, + xField, + yField, + title, + height = 260, + group, + colorField, + seriesField, + stack, + legend = undefined + } = props; const config = { data, xField, yField, - // colorField: 'name', + colorField: colorField || 'name', direction: 'vertical', + stack, + seriesField, height, - group: true, + group, scale: { x: { type: 'band', padding: 0.5 } }, - legend: { - color: { - position: 'top', - layout: { - justifyContent: 'center' - } - } - }, + legend: + legend === 'undefined' + ? { + color: { + position: 'top', + layout: { + justifyContent: 'center' + } + } + } + : legend, axis: { x: { xAxis: true, tick: false }, y: { - tick: false + tick: false, + labelAutoWrap: true } }, title: { @@ -61,7 +83,12 @@ const BarChart: React.FC = (props) => { }, style: { - fill: 'linear-gradient(90deg,rgba(84, 204, 152,0.8) 0%,rgb(0, 168, 143,.7) 100%)', + fill: (params: any) => { + return ( + params.color || + 'linear-gradient(90deg,rgba(84, 204, 152,0.8) 0%,rgb(0, 168, 143,.7) 100%)' + ); + }, radiusTopLeft: 12, radiusTopRight: 12, align: 'center', diff --git a/src/components/charts/h-bar.tsx b/src/components/charts/h-bar.tsx index 90486c88..4d6c9d15 100644 --- a/src/components/charts/h-bar.tsx +++ b/src/components/charts/h-bar.tsx @@ -6,25 +6,46 @@ interface BarChartProps { yField: string; title?: string; height?: number; + group?: boolean; + colorField?: string; + seriesField?: string; + stack?: boolean; + legend?: any; } const BarChart: React.FC = (props) => { - const { data, xField, yField, title, height } = props; + const { + data, + xField, + yField, + title, + height, + group, + colorField, + seriesField, + stack, + legend = undefined + } = props; const config = { data, xField, yField, - // colorField: 'name', + colorField: colorField || 'name', direction: 'vertical', + seriesField, height, - group: true, - legend: { - color: { - position: 'top', - layout: { - justifyContent: 'center' - } - } - }, + group, + stack, + legend: + legend === 'undefined' + ? { + color: { + position: 'top', + layout: { + justifyContent: 'center' + } + } + } + : legend, scale: { x: { type: 'band', @@ -59,7 +80,12 @@ const BarChart: React.FC = (props) => { }, markBackground: {}, style: { - fill: 'linear-gradient(180deg,rgba(84, 204, 152,0.8) 0%,rgb(0, 168, 143,.7) 100%)', + fill: (params: any) => { + return ( + params.color || + 'linear-gradient(90deg,rgba(84, 204, 152,0.8) 0%,rgb(0, 168, 143,.7) 100%)' + ); + }, radiusTopLeft: 12, radiusTopRight: 12, height: 20 diff --git a/src/components/charts/line-chart.tsx b/src/components/charts/line-chart.tsx index a61def13..f93ba481 100644 --- a/src/components/charts/line-chart.tsx +++ b/src/components/charts/line-chart.tsx @@ -7,10 +7,12 @@ interface LineChartProps { color?: string[]; xField?: string; yField?: string; - slider?: boolean; + labelFormatter?: (v: any) => string; + slider?: any; } const LineChart: React.FC = (props) => { - const { data, title, color, xField, yField, slider, height } = props; + const { data, title, color, xField, yField, slider, height, labelFormatter } = + props; const config = { title, height, @@ -28,7 +30,12 @@ const LineChart: React.FC = (props) => { } }, y: { - tick: false + tick: false, + // size: 14, + // title: '%', + titlePosition: 'top', + titleFontSize: 12, + labelFormatter } }, // point: { diff --git a/src/components/charts/liquid.tsx b/src/components/charts/liquid.tsx index aaf05915..3b7a0513 100644 --- a/src/components/charts/liquid.tsx +++ b/src/components/charts/liquid.tsx @@ -12,7 +12,7 @@ interface LiquidChartProps { } const LiquidChart: React.FC = (props) => { const { - percent, + percent = 0, color, title, width, diff --git a/src/global.less b/src/global.less index 3287b62f..b21d96e4 100644 --- a/src/global.less +++ b/src/global.less @@ -289,6 +289,14 @@ body { .ant-pro-sider { .ant-menu { + .ant-menu-item { + border-radius: 16px; + + &:active { + background-color: var(--ant-menu-item-selected-bg); + } + } + .ant-menu-item:not(.ant-menu-item-selected) { color: var(--ant-color-text); } @@ -300,6 +308,11 @@ body { .ant-menu-item.ant-menu-item-selected:hover { color: var(--ant-color-primary); } + + .ant-menu-item.ant-menu-item-selected { + color: var(--ant-color-primary); + background-color: unset; + } } } } diff --git a/src/pages/dashboard/apis/index.ts b/src/pages/dashboard/apis/index.ts index e69de29b..bb2d0661 100644 --- a/src/pages/dashboard/apis/index.ts +++ b/src/pages/dashboard/apis/index.ts @@ -0,0 +1,7 @@ +import { request } from '@umijs/max'; + +export const DASHBOARD_API = '/dashboard'; + +export async function queryDashboardData() { + return request(DASHBOARD_API); +} diff --git a/src/pages/dashboard/components/active-table.tsx b/src/pages/dashboard/components/active-table.tsx index d34b7923..ea065d84 100644 --- a/src/pages/dashboard/components/active-table.tsx +++ b/src/pages/dashboard/components/active-table.tsx @@ -1,6 +1,9 @@ -// import div from '@/components/content-wrapper'; import PageTools from '@/components/page-tools'; +import ProgressBar from '@/components/progress-bar'; import { Col, Row, Table } from 'antd'; +import _ from 'lodash'; +import { useContext } from 'react'; +import { DashboardContext } from '../config/dashboard-context'; const modelColumns = [ { @@ -9,28 +12,30 @@ const modelColumns = [ key: 'name' }, { - title: 'Allocated GPUs', - dataIndex: 'allocated', - key: 'allocated', - render: (text: any, record: any) => {record.gpu.allocated} + title: 'GPU Utilization', + dataIndex: 'gpu_utilization', + key: 'gpu_utilization', + render: (text: any, record: any) => ( + + ) }, { - title: 'GPU Utilization', - dataIndex: 'utilization', - key: 'utilization', - render: (text: any, record: any) => {record.gpu.utilization} + title: 'VRAM Utilization', + dataIndex: 'gpu_memory_utilization', + key: 'gpu_memory_utilization', + render: (text: any, record: any) => ( + + ) }, { title: 'Running Instances', - dataIndex: 'running', - key: 'running', - render: (text: any, record: any) => {record.instances.running} + dataIndex: 'instance_count', + key: 'instance_count' }, { - title: 'Pending Instances', - dataIndex: 'pending', - key: 'pending', - render: (text: any, record: any) => {record.instances.pending} + title: 'Tokens', + dataIndex: 'token_count', + key: 'token_count' } ]; @@ -59,39 +64,6 @@ const projectColumns = [ } ]; -const modelData = [ - { - id: 1, - name: 'qwen2', - gpu: { allocated: 4, utilization: '50%' }, - instances: { running: 1, pending: 0 } - }, - { - id: 2, - name: 'llama3:70b', - gpu: { allocated: 3, utilization: '70%' }, - instances: { running: 1, pending: 0 } - }, - { - id: 3, - name: 'llama3', - gpu: { allocated: 5, utilization: '20%' }, - instances: { running: 1, pending: 0 } - }, - { - id: 4, - name: 'gemma', - gpu: { allocated: 1, utilization: '25%' }, - instances: { running: 1, pending: 0 } - }, - { - id: 5, - name: 'phi3', - gpu: { allocated: 2, utilization: '46%' }, - instances: { running: 1, pending: 0 } - } -]; - const projectData = [ { id: 1, @@ -130,6 +102,7 @@ const projectData = [ } ]; const ActiveTable = () => { + const data = useContext(DashboardContext).active_models || []; return ( @@ -147,7 +120,7 @@ const ActiveTable = () => {
diff --git a/src/pages/dashboard/components/over-view.tsx b/src/pages/dashboard/components/over-view.tsx index ed1a8f67..46cf5de0 100644 --- a/src/pages/dashboard/components/over-view.tsx +++ b/src/pages/dashboard/components/over-view.tsx @@ -1,6 +1,8 @@ import { Card, Col, Row, Space } from 'antd'; -import React from 'react'; +import _ from 'lodash'; +import React, { useContext } from 'react'; import { overviewConfigs } from '../config'; +import { DashboardContext } from '../config/dashboard-context'; import '../styles/index.less'; import styles from './over-view.less'; @@ -23,23 +25,8 @@ const renderCardItem = (data: { ); }; -const Overview: React.FC = (props) => { - // const { data = {} } = props; - const data = { - workers: 8, - models: { - healthy: 10, - warning: 2, - error: 1 - }, - gpus: 30, - allocatedGpus: 12, - instances: { - healthy: 32, - warning: 3, - error: 2 - } - }; +const Overview: React.FC = () => { + const data = useContext(DashboardContext).resource_counts || {}; const renderValue = ( value: @@ -75,7 +62,7 @@ const Overview: React.FC = (props) => { > {renderCardItem({ label: config.label, - value: renderValue(data[config.key] || 0), + value: renderValue(_.get(data, config.key, 0)), bgColor: config.backgroundColor })} diff --git a/src/pages/dashboard/components/resource-utilization.tsx b/src/pages/dashboard/components/resource-utilization.tsx index c7c11dba..33cbb2b8 100644 --- a/src/pages/dashboard/components/resource-utilization.tsx +++ b/src/pages/dashboard/components/resource-utilization.tsx @@ -1,68 +1,68 @@ import LineChart from '@/components/charts/line-chart'; -import { generateFluctuatingData } from '@/utils'; +import dayjs from 'dayjs'; import _ from 'lodash'; +import { useContext, useEffect, useState } from 'react'; +import { DashboardContext } from '../config/dashboard-context'; -const mockData = { - GPU: generateFluctuatingData({ - total: 17, - max: 80, - min: 20 - }), - CPU: generateFluctuatingData({ - total: 17, - max: 70, - min: 10 - }), - Memory: generateFluctuatingData({ - total: 17, - max: 60, - min: 20 - }), - VRAM: generateFluctuatingData({ - total: 17, - max: 90, - min: 15 - }) +const TypeKeyMap = { + cpu: 'CPU', + memory: 'Memory', + gpu: 'GPU', + gpu_memory: 'VRAM' }; + const UtilizationOvertime: React.FC = () => { - const timeList = [ - '08:00:00', - '09:00:00', - '10:00:00', - '11:00:00', - '12:00:00', - '13:00:00', - '14:00:00', - '15:00:00', - '16:00:00', - '17:00:00', - '18:00:00', - '19:00:00', - '20:00:00', - '21:00:00', - '22:00:00', - '23:00:00', - '24:00:00' - ]; - const typeList = ['GPU', 'CPU', 'Memory', 'VRAM']; - const generateData = () => { - const data = []; - for (let i = 0; i < timeList.length; i++) { - for (let j = 0; j < typeList.length; j++) { - data.push({ - time: timeList[i], - type: typeList[j], - value: _.get(mockData, typeList[j])[i] - }); - } + const data = useContext(DashboardContext)?.system_load?.history || {}; + const [result, setResult] = useState< + { time: string; value: number; type: string }[] + >([]); + + const typeList = ['gpu', 'cpu', 'memory', 'gpu_memory']; + const sliderConfig = { + y: false, + x: { + style: { + selectionFill: 'rgb(84, 204, 152)', + selectionFillOpacity: 0.1, + handleIconFill: 'rgb(84, 204, 152)', + handleIconFillOpacity: 0.15, + handleIconStrokeOpacity: 0, + sparklineType: 'line', + sparkline: true + }, + sparkline: true } - return data; }; - const data = generateData(); + + const labelFormatter = (value: any) => { + return `${value}%`; + }; + const generateData = () => { + const list: { value: number; time: string; type: string }[] = []; + _.each(typeList, (type: any) => { + const dataList = _.map(_.get(data, type, []), (item: any) => { + return { + value: _.round(item.value, 2) || 0, + time: dayjs(item.timestamp * 1000).format('HH:mm:ss'), + type: _.get(TypeKeyMap, type, '') + }; + }); + list.push(...dataList); + }); + setResult(list); + }; + + useEffect(() => { + generateData(); + }, [data]); return ( <> - + ); }; diff --git a/src/pages/dashboard/components/system-load.tsx b/src/pages/dashboard/components/system-load.tsx index edd238c3..3a2a541e 100644 --- a/src/pages/dashboard/components/system-load.tsx +++ b/src/pages/dashboard/components/system-load.tsx @@ -4,7 +4,9 @@ import PageTools from '@/components/page-tools'; import breakpoints from '@/config/breakpoints'; import useWindowResize from '@/hooks/use-window-resize'; import { Col, DatePicker, Row } from 'antd'; -import { useEffect, useState } from 'react'; +import _ from 'lodash'; +import { useContext, useEffect, useState } from 'react'; +import { DashboardContext } from '../config/dashboard-context'; import ResourceUtilization from './resource-utilization'; const SystemLoad = () => { @@ -13,7 +15,7 @@ const SystemLoad = () => { 'linear-gradient(90deg, rgba(255, 214, 102,.8) 0%, rgba(255, 214, 102,0.5) 50%, rgba(255, 214, 102,.8) 100%)', 'linear-gradient(90deg, rgba(255, 120, 117,.8) 0%, rgba(255, 120, 117,0.5) 50%, rgba(255, 120, 117,.8) 100%)' ]; - + const data = useContext(DashboardContext)?.system_load?.current || {}; const { size } = useWindowResize(); const [paddingRight, setPaddingRight] = useState('20px'); const [smallChartHeight, setSmallChartHeight] = useState(190); @@ -64,7 +66,7 @@ const SystemLoad = () => { @@ -72,7 +74,9 @@ const SystemLoad = () => { @@ -80,7 +84,7 @@ const SystemLoad = () => { @@ -88,7 +92,9 @@ const SystemLoad = () => { diff --git a/src/pages/dashboard/components/usage.tsx b/src/pages/dashboard/components/usage.tsx index 0297d687..77245dd1 100644 --- a/src/pages/dashboard/components/usage.tsx +++ b/src/pages/dashboard/components/usage.tsx @@ -6,7 +6,10 @@ import breakpoints from '@/config/breakpoints'; import useWindowResize from '@/hooks/use-window-resize'; import { generateRandomArray } from '@/utils'; import { Col, DatePicker, Row } from 'antd'; -import { useEffect, useState } from 'react'; +import dayjs from 'dayjs'; +import _ from 'lodash'; +import { useContext, useEffect, useState } from 'react'; +import { DashboardContext } from '../config/dashboard-context'; const { RangePicker } = DatePicker; const times = [ @@ -92,9 +95,82 @@ const tokenUsage = TokensData.map((val, i) => { const Usage = () => { const { size } = useWindowResize(); const [paddingRight, setPaddingRight] = useState('20px'); + const [requestData, setRequestData] = useState< + { time: string; value: number }[] + >([]); + const [tokenData, setTokenData] = useState<{ time: string; value: number }[]>( + [] + ); + const [userData, setUserData] = useState<{ name: string; value: number }[]>( + [] + ); + const data = useContext(DashboardContext)?.model_usage || {}; const handleSelectDate = (dateString: string) => {}; + const generateData = () => { + const requestList: { time: string; value: number }[] = []; + const tokenList: { + time: string; + value: number; + name: string; + color: string; + }[] = []; + const userList: { + name: string; + value: number; + type: string; + color: string; + }[] = []; + + _.each(data.api_request_history, (item: any) => { + requestList.push({ + time: dayjs(item.timestamp * 1000).format('YYYY-MM-DD'), + value: item.value + }); + }); + + _.each(data.completion_token_history, (item: any) => { + tokenList.push({ + time: dayjs(item.timestamp * 1000).format('YYYY-MM-DD'), + name: 'completion_token', + color: + 'linear-gradient(90deg,rgba(84, 204, 152,0.8) 0%,rgb(0, 168, 143,.7) 100%)', + value: item.value + }); + }); + _.each(data.prompt_token_history, (item: any) => { + tokenList.push({ + time: dayjs(item.timestamp * 1000).format('YYYY-MM-DD'), + name: 'prompt_token', + color: + 'linear-gradient(90deg,rgba(0, 170, 173, 0.8) 0%,rgba(0, 109, 193, 0.7) 100%)', + value: item.value + }); + }); + + _.each(data.top_users, (item: any) => { + userList.push({ + name: item.username, + type: 'completion_token', + color: + 'linear-gradient(90deg,rgba(84, 204, 152,0.8) 0%,rgb(0, 168, 143,.7) 100%)', + value: item.completion_token_count + }); + userList.push({ + name: item.username, + type: 'prompt_token', + color: + 'linear-gradient(90deg,rgba(0, 170, 173, 0.8) 0%,rgba(0, 109, 193, 0.7) 100%)', + value: item.prompt_token_count + }); + }); + + setRequestData(requestList); + setTokenData(tokenList); + setUserData(userList); + }; + useEffect(() => { if (size.width < breakpoints.xl) { setPaddingRight('0'); @@ -103,6 +179,10 @@ const Usage = () => { } }, [size.width]); + useEffect(() => { + generateData(); + }, [data]); + return ( <> { { @@ -148,8 +232,11 @@ const Usage = () => { diff --git a/src/pages/dashboard/config/dashboard-context.ts b/src/pages/dashboard/config/dashboard-context.ts new file mode 100644 index 00000000..6d18d54e --- /dev/null +++ b/src/pages/dashboard/config/dashboard-context.ts @@ -0,0 +1,8 @@ +import { createContext } from 'react'; +import { DashboardProps } from './types'; + +export const DashboardContext = createContext( + {} as DashboardProps +); + +export default DashboardContext; diff --git a/src/pages/dashboard/config/index.ts b/src/pages/dashboard/config/index.ts index 790e5e04..56aec962 100644 --- a/src/pages/dashboard/config/index.ts +++ b/src/pages/dashboard/config/index.ts @@ -1,12 +1,12 @@ export const overviewConfigs = [ { - key: 'workers', + key: 'workworker_count', label: 'Workers', // backgroundColor: 'linear-gradient(135deg, #ffffff, rgb(232 249 240 / 60%))' backgroundColor: 'var(--color-white-1)' }, { - key: 'gpus', + key: 'gpu_count', label: 'Total GPUs', backgroundColor: 'var(--color-white-1)' // backgroundColor: 'linear-gradient(135deg, #ffffff, rgb(232 249 240 / 60%))' @@ -18,13 +18,13 @@ export const overviewConfigs = [ // backgroundColor: 'linear-gradient(135deg, #ffffff, rgb(232 249 240 / 60%))' }, { - key: 'models', + key: 'model_count', label: 'Models', backgroundColor: 'var(--color-white-1)' // backgroundColor: 'linear-gradient(135deg, #ffffff, rgb(232 249 240 / 60%))' }, { - key: 'instances', + key: 'model_instance_count', label: 'Instances', backgroundColor: 'var(--color-white-1)' // backgroundColor: 'linear-gradient(135deg, #ffffff, rgb(232 249 240 / 60%))' diff --git a/src/pages/dashboard/config/types.ts b/src/pages/dashboard/config/types.ts new file mode 100644 index 00000000..8080b65b --- /dev/null +++ b/src/pages/dashboard/config/types.ts @@ -0,0 +1,62 @@ +export interface DashboardProps { + resource_counts: { + worker_count: number; + gpu_count: number; + model_count: number; + model_instance_count: number; + }; + system_load: { + current: { + cpu: { + total: number; + used: number; + utilization_rate: number; + }; + memory: { + total: number; + used: number; + utilization_rate: number; + }; + gpu: { + total: number; + used: number; + utilization_rate: number; + }; + gpu_memory: { + total: number; + used: number; + utilization_rate: number; + }; + }; + history: { + cpu: { + timestamp: number; + value: number; + }[]; + memory: { + timestamp: number; + value: number; + }[]; + gpu: { + timestamp: number; + value: number; + }[]; + gpu_memory: { + timestamp: number; + value: number; + }[]; + }; + }; + model_usage: { + api_request_history: any[]; + completion_token_history: any[]; + prompt_token_history: any[]; + top_users: { + user_id: number; + username: string; + prompt_token_count: number; + completion_token_count: number; + }[]; + }; + active_models: any[]; +} diff --git a/src/pages/dashboard/index.tsx b/src/pages/dashboard/index.tsx index c8fbd297..8edbaf48 100644 --- a/src/pages/dashboard/index.tsx +++ b/src/pages/dashboard/index.tsx @@ -1,16 +1,40 @@ +import { Spin } from 'antd'; +import { useEffect, useState } from 'react'; +import { queryDashboardData } from './apis'; import ActiveTable from './components/active-table'; import Overview from './components/over-view'; import SystemLoad from './components/system-load'; import Usage from './components/usage'; +import DashboardContext from './config/dashboard-context'; +import { DashboardProps } from './config/types'; const Dashboard: React.FC = () => { + const [data, setData] = useState({} as DashboardProps); + const [loading, setLoading] = useState(false); + + const getDashboardData = async () => { + try { + setLoading(true); + const res = await queryDashboardData(); + setData(res); + setLoading(false); + } catch (error) { + setLoading(false); + setData({} as DashboardProps); + } + }; + useEffect(() => { + getDashboardData(); + }, []); return ( - <> - - - - - + + + + + + + + ); }; diff --git a/src/pages/llmodels/components/add-modal.tsx b/src/pages/llmodels/components/add-modal.tsx index a89aafba..16714687 100644 --- a/src/pages/llmodels/components/add-modal.tsx +++ b/src/pages/llmodels/components/add-modal.tsx @@ -26,7 +26,7 @@ type AddModalProps = { const sourceOptions = [ { label: 'Huggingface', value: 'huggingface', key: 'huggingface' }, - { label: 'Ollama', value: 'ollama_library', key: 'ollama_library' } + { label: 'Ollama Library', value: 'ollama_library', key: 'ollama_library' } ]; const AddModal: React.FC = (props) => { diff --git a/src/pages/llmodels/index.tsx b/src/pages/llmodels/index.tsx index d7d1fa86..ff0b0f67 100644 --- a/src/pages/llmodels/index.tsx +++ b/src/pages/llmodels/index.tsx @@ -114,7 +114,7 @@ const Models: React.FC = () => { clearInterval(timer.current); timer.current = setInterval(() => { fetchData(true); - }, 3000); + }, 5000); }; const handleShowSizeChange = (page: number, size: number) => { diff --git a/src/pages/playground/components/chat-footer.tsx b/src/pages/playground/components/chat-footer.tsx index fa3cf394..d1e02365 100644 --- a/src/pages/playground/components/chat-footer.tsx +++ b/src/pages/playground/components/chat-footer.tsx @@ -18,11 +18,20 @@ interface ChatFooterProps { onView: () => void; disabled?: boolean; feedback?: React.ReactNode; + hasTokenResult?: boolean; } const ChatFooter: React.FC = (props) => { const intl = useIntl(); - const { onSubmit, onClear, onNewMessage, onView, feedback, disabled } = props; + const { + onSubmit, + onClear, + onNewMessage, + onView, + feedback, + disabled, + hasTokenResult + } = props; useHotkeys( HotKeys.SUBMIT.join(','), () => { @@ -34,7 +43,7 @@ const ChatFooter: React.FC = (props) => { return (
-
+ - {feedback} - + {feedback} +
);