修复管理员界面相关问题,优化页面显示

This commit is contained in:
sijinhui 2023-12-29 23:49:26 +08:00
parent d5e92a7b06
commit 067ccb481b
3 changed files with 158 additions and 144 deletions

View File

@ -6,6 +6,7 @@ import { insertUser } from "@/lib/auth";
// import cl100k_base from "tiktoken/encoders/cl100k_base.json" // import cl100k_base from "tiktoken/encoders/cl100k_base.json"
import "tiktoken"; import "tiktoken";
import { get_encoding } from "tiktoken"; import { get_encoding } from "tiktoken";
import { addHours, subMinutes } from "date-fns";
function getTokenLength(input: string): number { function getTokenLength(input: string): number {
// const { Tiktoken } = require("tiktoken/lite"); // const { Tiktoken } = require("tiktoken/lite");
@ -45,6 +46,10 @@ async function handle(
console.log("[LOG]", "logToken", e); console.log("[LOG]", "logToken", e);
request_data.logToken = 0; request_data.logToken = 0;
} }
// 默认时间不准,还是手动获取一下吧。
// 转换时区太麻烦,我还是直接减去时差
// const current_time = new Date();
// request_data.createdAt = subMinutes(current_time, current_time.getTimezoneOffset())
await prisma.logEntry.create({ await prisma.logEntry.create({
data: request_data, data: request_data,

View File

@ -2,7 +2,9 @@ import * as echarts from "echarts";
import { EChartsOption } from "echarts"; import { EChartsOption } from "echarts";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import prisma from "@/lib/prisma"; import prisma from "@/lib/prisma";
import { addHours } from "date-fns"; import { addHours, subMinutes } from "date-fns";
import { log } from "util";
import { use } from "react";
// import { getTokenLength } from "@/app/utils/token"; // import { getTokenLength } from "@/app/utils/token";
@ -10,53 +12,60 @@ const UsageByModelChart = dynamic(() => import("./usage-by-model-chart"), {
ssr: false, ssr: false,
}); });
interface StringKeyedObject {
[key: string]: { [key: string]: number };
}
// interface StringArray {
// strings: string[];
// }
type StringSet = Set<string>;
type StringArray = string[];
function HandleLogData( function HandleLogData(
todayLog: [{ userName: string; logEntry: string; logToken: number }], todayLog: [{ userName: string; logToken: number; model: string }],
) { ) {
const data1 = todayLog.map((log) => { // 先遍历一遍,获取所有的模型和名字。
let all_models: StringSet = new Set();
let all_names: StringSet = new Set();
// 拼接数据结构
let data_by_name: StringKeyedObject = {};
todayLog.map((log) => {
all_models.add(log.model);
all_names.add(log.userName);
data_by_name[log.userName] = data_by_name[log.userName] ?? {};
data_by_name[log.userName][log.model] =
(data_by_name[log.userName][log.model] || 0) + log.logToken;
// 这么顺利,顺便加个总数吧。
data_by_name[log.userName]["all_token"] =
(data_by_name[log.userName]["all_token"] || 0) + log.logToken;
});
//
// 然后遍历并以all_token排序。
const userNameList: StringArray = Array.from(all_names).sort((a, b) => {
return data_by_name[a]["all_token"] - data_by_name[b]["all_token"];
});
// 将值按模型分为两个序列
const modelNameList = Array.from(all_models).map((model) => {
return { return {
name: log.userName ?? "unknown", name: model,
value: log.logToken, data: userNameList.map((userName) => {
return data_by_name[userName][model] ?? null;
}),
}; };
}); });
console.log("看看", modelNameList);
type Accumulator = { return {
[key: string]: number; modelNameList,
userNameList,
data_by_name,
}; };
const data2 = data1.reduce<Accumulator>((acc, item) => {
if (acc[item.name]) {
acc[item.name] += item.value;
} else {
acc[item.name] = item.value;
}
return acc;
}, {});
const data3 = Object.entries(data2)
.map(([name, value]) => ({
name,
value,
}))
.sort((a, b) => {
return a.value - b.value;
});
const data4 = data3.reduce(
(acc, cur) => {
// @ts-ignore
acc.name.push(cur.name);
// @ts-ignore
acc.value.push(cur.value);
return acc;
},
{ name: [], value: [] },
);
return data4;
} }
export default async function UsageByModel() { export default async function UsageByModel() {
// 今天日期的开始和结束 // 今天日期的开始和结束
var today = new Date(); var today = new Date();
today = addHours(today, +8); // today = subMinutes(today, today.getTimezoneOffset())
const startOfTheDayInTimeZone = new Date( const startOfTheDayInTimeZone = new Date(
today.getFullYear(), today.getFullYear(),
today.getMonth(), today.getMonth(),
@ -65,19 +74,7 @@ export default async function UsageByModel() {
0, 0,
0, 0,
); );
// const endOfTheDayInTimeZone = new Date(
// today.getFullYear(),
// today.getMonth(),
// today.getDate(),
// 23,
// 59,
// 59,
// ); // 当天的结束时间
const endOfTheDayInTimeZone = addHours(startOfTheDayInTimeZone, +24); // 当天的结束时间 const endOfTheDayInTimeZone = addHours(startOfTheDayInTimeZone, +24); // 当天的结束时间
// const startDate = addHours(startOfTheDayInTimeZone, -8);
// const endDate = addHours(endOfTheDayInTimeZone, -8);
console.log("===", today, startOfTheDayInTimeZone, endOfTheDayInTimeZone);
const todayLog = await prisma.logEntry.findMany({ const todayLog = await prisma.logEntry.findMany({
where: { where: {
createdAt: { createdAt: {
@ -89,13 +86,9 @@ export default async function UsageByModel() {
user: true, user: true,
}, },
}); });
// console.log("========", todayLog[todayLog.length - 1]);
// @ts-ignore // @ts-ignore
const log_data = HandleLogData(todayLog); const log_data = HandleLogData(todayLog);
console.log("[log_data]====---==", todayLog);
const usageByModelOption: EChartsOption = { const usageByModelOption: EChartsOption = {
tooltip: { tooltip: {
trigger: "axis", trigger: "axis",
@ -122,12 +115,12 @@ export default async function UsageByModel() {
yAxis: [ yAxis: [
{ {
type: "category", type: "category",
data: log_data.name, data: log_data.userNameList,
}, },
], ],
series: [ series: log_data.modelNameList.map((item) => {
{ return {
name: "总量", ...item,
type: "bar", type: "bar",
emphasis: { emphasis: {
focus: "series", focus: "series",
@ -136,91 +129,107 @@ export default async function UsageByModel() {
show: true, show: true,
position: "right", position: "right",
}, },
colorBy: "data", colorBy: "series",
// progress: { stack: "model",
// show: true };
// }, }),
data: log_data.value,
}, // [
// { // {
// name: 'Email', // name: "总量",
// type: 'bar', // type: "bar",
// stack: 'Ad', // emphasis: {
// emphasis: { // focus: "series",
// focus: 'series' // },
// }, // label: {
// data: [120, 132, 101, 134, 90, 230, 210] // show: true,
// }, // position: "right",
// { // },
// name: 'Union Ads', // colorBy: "data",
// type: 'bar', // // progress: {
// stack: 'Ad', // // show: true
// emphasis: { // // },
// focus: 'series' // data: log_data.value,
// }, // },
// data: [220, 182, 191, 234, 290, 330, 310] // {
// }, // name: 'Email',
// { // type: 'bar',
// name: 'Video Ads', // stack: 'Ad',
// type: 'bar', // emphasis: {
// stack: 'Ad', // focus: 'series'
// emphasis: { // },
// focus: 'series' // data: [120, 132, 101, 134, 90, 230, 210]
// }, // },
// data: [150, 232, 201, 154, 190, 330, 410] // {
// }, // name: 'Union Ads',
// { // type: 'bar',
// name: 'Search Engine', // stack: 'Ad',
// type: 'bar', // emphasis: {
// data: [862, 1018, 964, 1026, 1679, 1600, 1570], // focus: 'series'
// emphasis: { // },
// focus: 'series' // data: [220, 182, 191, 234, 290, 330, 310]
// }, // },
// // markLine: { // {
// // lineStyle: { // name: 'Video Ads',
// // type: 'dashed' // type: 'bar',
// // }, // stack: 'Ad',
// // data: [[{ type: 'min' }, { type: 'max' }]] // emphasis: {
// // } // focus: 'series'
// }, // },
// { // data: [150, 232, 201, 154, 190, 330, 410]
// name: 'Baidu', // },
// type: 'bar', // {
// barWidth: 5, // name: 'Search Engine',
// stack: 'Search Engine', // type: 'bar',
// emphasis: { // data: [862, 1018, 964, 1026, 1679, 1600, 1570],
// focus: 'series' // emphasis: {
// }, // focus: 'series'
// data: [620, 732, 701, 734, 1090, 1130, 1120] // },
// }, // // markLine: {
// { // // lineStyle: {
// name: 'Google', // // type: 'dashed'
// type: 'bar', // // },
// stack: 'Search Engine', // // data: [[{ type: 'min' }, { type: 'max' }]]
// emphasis: { // // }
// focus: 'series' // },
// }, // {
// data: [120, 132, 101, 134, 290, 230, 220] // name: 'Baidu',
// }, // type: 'bar',
// { // barWidth: 5,
// name: 'Bing', // stack: 'Search Engine',
// type: 'bar', // emphasis: {
// stack: 'Search Engine', // focus: 'series'
// emphasis: { // },
// focus: 'series' // data: [620, 732, 701, 734, 1090, 1130, 1120]
// }, // },
// data: [60, 72, 71, 74, 190, 130, 110] // {
// }, // name: 'Google',
// { // type: 'bar',
// name: 'Others', // stack: 'Search Engine',
// type: 'bar', // emphasis: {
// stack: 'Search Engine', // focus: 'series'
// emphasis: { // },
// focus: 'series' // data: [120, 132, 101, 134, 290, 230, 220]
// }, // },
// data: [62, 82, 91, 84, 109, 110, 120] // {
// } // name: 'Bing',
], // type: 'bar',
// stack: 'Search Engine',
// emphasis: {
// focus: 'series'
// },
// data: [60, 72, 71, 74, 190, 130, 110]
// },
// {
// name: 'Others',
// type: 'bar',
// stack: 'Search Engine',
// emphasis: {
// focus: 'series'
// },
// data: [62, 82, 91, 84, 109, 110, 120]
// }
// ],
}; };
return ( return (
<> <>

View File

@ -252,7 +252,7 @@ function isPinYin(input: string): boolean {
export function isName(input: string): boolean { export function isName(input: string): boolean {
const denyList = [ const denyList = [
"suibian", "suibian", "某某", "张三", "李四"
] ]
if (denyList.includes(input)) { if (denyList.includes(input)) {
return false; return false;
@ -300,4 +300,4 @@ function cleanUpString(input: string): string {
catch { catch {
return ''; return '';
} }
} }