perf: do not handle ansi sequence for parsing logs
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
@@ -53,7 +53,7 @@ const BarChart: React.FC<ChartProps & { maxItems?: number }> = (props) => {
|
|||||||
axisLabel: {
|
axisLabel: {
|
||||||
...yAxis.axisLabel,
|
...yAxis.axisLabel,
|
||||||
overflow: 'truncate',
|
overflow: 'truncate',
|
||||||
width: 60,
|
width: 75,
|
||||||
ellipsis: '...'
|
ellipsis: '...'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ const MixLineBarChart: React.FC<
|
|||||||
stack: 'total',
|
stack: 'total',
|
||||||
yAxisIndex: 0,
|
yAxisIndex: 0,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
|
...item.itemStyle,
|
||||||
color: item.color
|
color: item.color
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ class AnsiParser {
|
|||||||
private percent: number = 0;
|
private percent: number = 0;
|
||||||
private isComplete: boolean = false;
|
private isComplete: boolean = false;
|
||||||
private chunked: boolean = true; // true: send data in chunks, false: send all data at once
|
private chunked: boolean = true; // true: send data in chunks, false: send all data at once
|
||||||
|
private reminder: string = '';
|
||||||
|
private lines: string[] = [];
|
||||||
private pageSize: number = 500;
|
private pageSize: number = 500;
|
||||||
private colorMap = {
|
private colorMap = {
|
||||||
'30': 'black',
|
'30': 'black',
|
||||||
@@ -52,6 +54,8 @@ class AnsiParser {
|
|||||||
this.screen = [['']];
|
this.screen = [['']];
|
||||||
this.rawDataRows = 0;
|
this.rawDataRows = 0;
|
||||||
this.uid = this.uid + 1;
|
this.uid = this.uid + 1;
|
||||||
|
this.lines = [];
|
||||||
|
this.reminder = '';
|
||||||
this.page = 1;
|
this.page = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +113,6 @@ class AnsiParser {
|
|||||||
const n = parseInt(match[1] || '1', 10);
|
const n = parseInt(match[1] || '1', 10);
|
||||||
const m = parseInt(match[2] || '1', 10);
|
const m = parseInt(match[2] || '1', 10);
|
||||||
const command = match[3];
|
const command = match[3];
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'A':
|
case 'A':
|
||||||
this.cursorRow = Math.max(0, this.cursorRow - n);
|
this.cursorRow = Math.max(0, this.cursorRow - n);
|
||||||
@@ -183,6 +186,28 @@ class AnsiParser {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private processInputByLine(input: string): {
|
||||||
|
data: string[];
|
||||||
|
lines: number;
|
||||||
|
remainder: string;
|
||||||
|
} {
|
||||||
|
const lines = input?.split(/\r?\n/) || [];
|
||||||
|
const remainder = lines.pop() || '';
|
||||||
|
|
||||||
|
// const data = lines.join('\n');
|
||||||
|
this.rawDataRows += lines.length;
|
||||||
|
this.lines.push(...lines);
|
||||||
|
return {
|
||||||
|
data: this.lines,
|
||||||
|
lines: this.rawDataRows,
|
||||||
|
remainder
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAllLines() {
|
||||||
|
return this.lines.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
private async processQueue(): Promise<void> {
|
private async processQueue(): Promise<void> {
|
||||||
if (this.isProcessing) {
|
if (this.isProcessing) {
|
||||||
return;
|
return;
|
||||||
@@ -191,11 +216,12 @@ class AnsiParser {
|
|||||||
this.isProcessing = true;
|
this.isProcessing = true;
|
||||||
|
|
||||||
while (this.taskQueue.length > 0) {
|
while (this.taskQueue.length > 0) {
|
||||||
const input = this.taskQueue.shift();
|
const input = this.reminder + this.taskQueue.shift();
|
||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
try {
|
try {
|
||||||
const result = this.processInput(input);
|
const result = this.processInputByLine(input);
|
||||||
|
this.reminder = result.remainder;
|
||||||
if (this.chunked) {
|
if (this.chunked) {
|
||||||
self.postMessage({ result: result.data, lines: result.lines });
|
self.postMessage({ result: result.data, lines: result.lines });
|
||||||
} else if (!this.isComplete) {
|
} else if (!this.isComplete) {
|
||||||
@@ -220,7 +246,7 @@ class AnsiParser {
|
|||||||
this.processQueue();
|
this.processQueue();
|
||||||
} else if (this.isComplete && !this.chunked) {
|
} else if (this.isComplete && !this.chunked) {
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
result: this.getScreenText(),
|
result: this.getAllLines(),
|
||||||
percent: this.percent,
|
percent: this.percent,
|
||||||
isComplete: true
|
isComplete: true
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const LogsViewer: React.FC<LogsViewerProps> = forwardRef((props, ref) => {
|
|||||||
const pageRef = useRef<any>(page);
|
const pageRef = useRef<any>(page);
|
||||||
const totalPageRef = useRef<any>(totalPage);
|
const totalPageRef = useRef<any>(totalPage);
|
||||||
const isLoadingMoreRef = useRef(false);
|
const isLoadingMoreRef = useRef(false);
|
||||||
const [currentData, setCurrentData] = useState<any[]>([]);
|
const [currentData, setCurrentPageData] = useState<any[]>([]);
|
||||||
const scrollPosRef = useRef<any>({
|
const scrollPosRef = useRef<any>({
|
||||||
pos: 'bottom',
|
pos: 'bottom',
|
||||||
page: 1
|
page: 1
|
||||||
@@ -59,6 +59,21 @@ const LogsViewer: React.FC<LogsViewerProps> = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const removeBracketsFromLine = (row: string) => {
|
||||||
|
return row.startsWith('(…)') ? row.slice(3) : row;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCurrentData = (lines: string[]) => {
|
||||||
|
const dataList = lines.map((line, index) => {
|
||||||
|
return {
|
||||||
|
content: removeBracketsFromLine(line),
|
||||||
|
uid: `${pageRef.current}-${index}`
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setCurrentPageData(dataList);
|
||||||
|
};
|
||||||
|
|
||||||
const debounceLoading = _.debounce(() => {
|
const debounceLoading = _.debounce(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
isLoadingMoreRef.current = false;
|
isLoadingMoreRef.current = false;
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ const ExportData: React.FC<{
|
|||||||
init();
|
init();
|
||||||
} else {
|
} else {
|
||||||
setQuery({
|
setQuery({
|
||||||
start_date: dayjs().subtract(30, 'days').format('YYYY-MM-DD'),
|
start_date: dayjs().subtract(29, 'days').format('YYYY-MM-DD'),
|
||||||
end_date: dayjs().format('YYYY-MM-DD'),
|
end_date: dayjs().format('YYYY-MM-DD'),
|
||||||
model_ids: [],
|
model_ids: [],
|
||||||
user_ids: []
|
user_ids: []
|
||||||
|
|||||||
@@ -50,11 +50,19 @@ const UsageInner: FC<{ maxWidth: number }> = ({ maxWidth }) => {
|
|||||||
const topUserNames = topUsers.map((item: any) => {
|
const topUserNames = topUsers.map((item: any) => {
|
||||||
topUserPrompt.data.push({
|
topUserPrompt.data.push({
|
||||||
name: item.username,
|
name: item.username,
|
||||||
value: item.prompt_token_count
|
value: item.prompt_token_count,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: !item.completion_token_count
|
||||||
|
? [2, 2, 2, 2]
|
||||||
|
: [0, 2, 2, 0]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
topUserCompletion.data.push({
|
topUserCompletion.data.push({
|
||||||
name: item.username,
|
name: item.username,
|
||||||
value: item.completion_token_count
|
value: item.completion_token_count,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: !item.prompt_token_count ? [2, 2, 2, 2] : [2, 0, 0, 2]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return item.username;
|
return item.username;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ const generateValueMap = (list: { timestamp: number; value: number }[]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const generateData = (dateRage: string[], valueMap: Map<string, number>) => {
|
const generateData = (dateRage: string[], valueMap: Map<string, number>) => {
|
||||||
return dateRage.map((date) => {
|
return dateRage.map((date, index) => {
|
||||||
const value = valueMap.get(date) || 0;
|
const value = valueMap.get(date) || 0;
|
||||||
return {
|
return {
|
||||||
time: date,
|
time: date,
|
||||||
@@ -201,15 +201,40 @@ export default function useUseageData<T>(config: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// =========== token usage data ==============
|
// =========== token usage data ==============
|
||||||
|
const completionDataList = generateData(
|
||||||
|
dateRange,
|
||||||
|
generateValueMap(completionTokenHistory)
|
||||||
|
);
|
||||||
|
const promptDataList = generateData(
|
||||||
|
dateRange,
|
||||||
|
generateValueMap(promptTokenHistory)
|
||||||
|
);
|
||||||
|
|
||||||
const completionData: any = {
|
const completionData: any = {
|
||||||
name: 'Completion tokens',
|
name: 'Completion tokens',
|
||||||
color: baseColorMap.base,
|
color: baseColorMap.base,
|
||||||
data: generateData(dateRange, generateValueMap(completionTokenHistory))
|
data: completionDataList.map((item, index) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: !promptDataList[index].value
|
||||||
|
? [2, 2, 0, 0]
|
||||||
|
: [0, 0, 0, 0]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
};
|
};
|
||||||
const promptData: any = {
|
const promptData: any = {
|
||||||
name: 'Prompt tokens',
|
name: 'Prompt tokens',
|
||||||
color: baseColorMap.baseR3,
|
color: baseColorMap.baseR3,
|
||||||
data: generateData(dateRange, generateValueMap(promptTokenHistory))
|
data: promptDataList.map((item, index) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: [2, 2, 0, 0]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user