diff --git a/client/demo/package-lock.json b/client/demo/package-lock.json index ccfedfbfc..c7c8a423e 100644 --- a/client/demo/package-lock.json +++ b/client/demo/package-lock.json @@ -16,7 +16,9 @@ "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", + "chart.js": "^4.4.3", "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", "react-toastify": "^10.0.5" }, @@ -3145,6 +3147,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -5215,6 +5222,17 @@ "node": ">=4" } }, + "node_modules/chart.js": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz", + "integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -10146,6 +10164,15 @@ "node": ">=0.10.0" } }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", diff --git a/client/demo/package.json b/client/demo/package.json index 27a31837a..22768a475 100644 --- a/client/demo/package.json +++ b/client/demo/package.json @@ -61,7 +61,9 @@ "@fortawesome/free-regular-svg-icons": "^6.5.1", "@fortawesome/free-solid-svg-icons": "^6.5.1", "@fortawesome/react-fontawesome": "^0.2.0", + "chart.js": "^4.4.3", "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", "react-toastify": "^10.0.5" } diff --git a/client/demo/src/components/demo/components2/101-0_Portrait.tsx b/client/demo/src/components/demo/components2/101-0_Portrait.tsx index e30ec8823..7ab178a12 100644 --- a/client/demo/src/components/demo/components2/101-0_Portrait.tsx +++ b/client/demo/src/components/demo/components2/101-0_Portrait.tsx @@ -1,6 +1,30 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; import { useAppState } from "../../../001_provider/001_AppStateProvider"; import { useMessageBuilder } from "../../../hooks/useMessageBuilder"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + LineController, + Filler, + } from 'chart.js'; +import { Chart } from 'react-chartjs-2'; + +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + LineController, + Filler, +); + export type PortraitProps = {}; // @ts-ignore @@ -9,11 +33,14 @@ export const Portrait = (_props: PortraitProps) => { const { serverSetting, performance } = useAppState(); const messageBuilderState = useMessageBuilder(); + const [perfTooltip, setPerfTooltip] = useState(0); + const elPerfChartRef = useRef(null); const elVolRef = useRef(null); const elChunkTimeRef = useRef(null); const elPingRef = useRef(null); const elTotalRef = useRef(null); const elPerfRef = useRef(null); + const MAX_DATA_POINTS = 50; const [lastReport, setLastReport] = useState(Date.now()) @@ -30,7 +57,7 @@ export const Portrait = (_props: PortraitProps) => { }, [serverSetting.serverSetting.modelSlotIndex, serverSetting.serverSetting.modelSlots]); useEffect(() => { - if (!elVolRef.current || !elChunkTimeRef.current || !elPingRef.current || !elTotalRef.current || !elPerfRef.current) { + if (!elVolRef.current || !elPerfChartRef.current || !elChunkTimeRef.current || !elPingRef.current || !elTotalRef.current || !elPerfRef.current) { return; } @@ -57,8 +84,36 @@ export const Portrait = (_props: PortraitProps) => { elPingRef.current.innerHTML = performance.responseTime.toString(); elTotalRef.current.innerHTML = totalLatencyTime.toString(); elPerfRef.current.innerHTML = performance.mainprocessTime.toString(); + + if (performance.mainprocessTime > 0) { + if (elPerfChartRef.current.data.labels!.length > MAX_DATA_POINTS) { + elPerfChartRef.current.data.labels!.shift() + elPerfChartRef.current.data.datasets[0].data.shift(); + } + elPerfChartRef.current.data.labels!.push(Date.now()) + elPerfChartRef.current.data.datasets[0].data.push(performance.mainprocessTime) + elPerfChartRef.current.update('none') + } }, [performance, serverSetting.serverSetting.crossFadeOverlapSize, serverSetting.serverSetting.serverReadChunkSize]) + useEffect(() => { + if (!elPerfRef.current) { + return + } + + const chunkTime = ((serverSetting.serverSetting.serverReadChunkSize * 128 * 1000) / 48000); + + if (perfTooltip > chunkTime) { + elPerfRef.current.style.color = '#ff4a4a'; + } else if (perfTooltip * 1.2 > chunkTime) { + elPerfRef.current.style.color = '#ffff00'; + } else { + elPerfRef.current.style.color = '#00ff00'; + } + + elPerfRef.current.innerHTML = perfTooltip.toString(); + }, [perfTooltip]) + const portrait = useMemo(() => { if (!selected) { return <>; @@ -75,6 +130,69 @@ export const Portrait = (_props: PortraitProps) => { <> ); + const options = { + responsive: true, + maintainAspectRatio: true, + interaction: { + mode: 'nearest', + axis: 'x', + intersect: false, + }, + layout: { + padding: { + left: -10, + bottom: -10, + } + }, + plugins: { + tooltip: { + enabled: false, + external: (context: any) => { + if (context.tooltip.dataPoints) { + setPerfTooltip(context.tooltip.dataPoints[0].parsed.y) + } + } + }, + title: { + display: false, + }, + }, + scales: { + x: { + ticks: { + display: false, + }, + min: 0, + grid: { + display: false + }, + }, + y: { + ticks: { + display: false, + }, + min: 0, + grid: { + display: false + }, + } + }, + }; + + const data = { + labels: [], + datasets: [ + { + data: [], + fill: true, + borderColor: 'rgb(75, 192, 192)', + backgroundColor: 'rgba(75, 192, 192, 0.5)', + pointRadius: 0, + borderWidth: 1, + } + ] + } + return (
@@ -95,6 +213,9 @@ export const Portrait = (_props: PortraitProps) => {

perf: 0 of 0 ms

+
+ +
{selectedTermOfUseUrlLink}
diff --git a/client/demo/src/css/App.css b/client/demo/src/css/App.css index 1234995eb..1231269f7 100644 --- a/client/demo/src/css/App.css +++ b/client/demo/src/css/App.css @@ -1313,7 +1313,7 @@ body { background: var(--company-color2); color: white; position: absolute; - padding: 0px 0px 0px 3px; + padding: 3px; font-size: 0.7rem; left: 5px; top: 5px;