mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-01 23:56:39 +08:00
修复管理员界面相关问题,优化页面显示
This commit is contained in:
parent
d5e92a7b06
commit
067ccb481b
@ -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,
|
||||||
|
@ -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 (
|
||||||
<>
|
<>
|
||||||
|
@ -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 '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user