Skip to content

Commit

Permalink
poekmon shared instance stats
Browse files Browse the repository at this point in the history
  • Loading branch information
moeakwak committed Jun 1, 2024
1 parent 4ad1283 commit 5937f58
Show file tree
Hide file tree
Showing 8 changed files with 534 additions and 256 deletions.
14 changes: 12 additions & 2 deletions src/app/(panel)/_components/instance-info-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { ChatGPTSharedInstanceGpt4UsageList } from "./chatgpt-shared/chatgpt-gpt
import { type ServiceInstance } from "@/schema/serviceInstance.schema";
import { PoekmonAPIInstanceUsageStatistics } from "./poekmon-api/poekmon-api-statistics";
import { PoekmonAPIModelUsage } from "./poekmon-api/poekmon-api-model-usage";
import { PoekmonSharedInstanceUsageStatistics } from "./poekmon-shared/poekmon-shared-statistics";
import PoekmonSharedAccountUsage from "./poekmon-shared/poekmon-shared-account-usage";

interface Props extends React.HTMLAttributes<HTMLFormElement> {
instance: ServiceInstance;
Expand All @@ -26,8 +28,6 @@ export function SharedChatGPTCardContent({ instance }: { instance: ServiceInstan
}

export function PoekmonAPICardContent({ instance }: { instance: ServiceInstance }) {


return (
<div className="grid gap-4 md:grid-cols-2">
<PoekmonAPIModelUsage instanceId={instance.id} />
Expand All @@ -36,6 +36,15 @@ export function PoekmonAPICardContent({ instance }: { instance: ServiceInstance
);
}

export function PoekmonSharedCardContent({ instance }: { instance: ServiceInstance }) {
return (
<div className="grid gap-4 md:grid-cols-2">
<PoekmonSharedAccountUsage instanceId={instance.id} />
<PoekmonSharedInstanceUsageStatistics instanceId={instance.id} />
</div>
);
}

export function InstanceInfoCard({ instance, className, children }: Props) {
return (
<Card className={cn("max-w-full overflow-x-hidden", className)}>
Expand All @@ -48,6 +57,7 @@ export function InstanceInfoCard({ instance, className, children }: Props) {
<CardContent className="py-3">
{instance.type === "CHATGPT_SHARED" && <SharedChatGPTCardContent instance={instance} />}
{instance.type === "POEKMON_API" && <PoekmonAPICardContent instance={instance} />}
{instance.type === "POEKMON_SHARED" && <PoekmonSharedCardContent instance={instance} />}
</CardContent>
<CardFooter className="border-t py-3">{children}</CardFooter>
</Card>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"use client";

import { cn } from "@/lib/utils";
import { Progress } from "@/components/ui/progress";
import StatusLabel from "@/components/custom/status-label";
import { type PoekmonSharedInstanceData } from "@/schema/service/poekmon-shared.schema";
import { api } from "@/trpc/react";

export default function PoekmonSharedAccountUsage({
instanceId,
className,
}: {
instanceId: string;
className?: string;
}) {
const accountInfoQuery = api.serviceInstance.getPoekmonSharedAccountInfo.useQuery({ id: instanceId });

const getBackgroundColor = (value: number) => {
let color;
if (value < 0.2) {
color = "bg-green-500";
} else if (value < 0.6) {
color = "bg-yellow-500";
} else if (value < 0.9) {
color = "bg-orange-500";
} else {
color = "bg-red-500";
}
return color;
};

let alloment = "n/a";
let balance = "n/a";
let percentage = 0;
let message_point_reset_time = "n/a";
const accountInfo = accountInfoQuery.data;
if (accountInfo !== null && accountInfo !== undefined) {
alloment = accountInfo.message_point_alloment.toString();
balance = accountInfo.message_point_balance.toString();
if (accountInfo.message_point_alloment !== 0) {
percentage = 1 - accountInfo.message_point_balance / accountInfo.message_point_alloment;
}
message_point_reset_time = new Date(accountInfo.message_point_reset_time / 1000).toLocaleString();
}

return (
<div className={cn("flex w-full flex-col", className)}>
<span className="text-md my-3 font-semibold">Poe 账号概况</span>
<div className="flex w-full flex-col space-y-2">
<div className="flex w-full max-w-[500px] flex-row items-center justify-between text-sm">
<span>积分使用情况</span>
<div className="flex flex-row items-center space-x-2">
<span>
{balance} / {alloment}
</span>
<Progress
value={Math.min(percentage * 100, 100)}
className={cn("w-[120px] max-w-full md:w-[200px]")}
indicatorClassName={getBackgroundColor(percentage)}
/>
</div>
</div>
<div className="flex w-full max-w-[500px] flex-row items-center justify-between text-sm">
<span>积分刷新时间</span>
<div className="flex flex-row items-center space-x-2">
<span>{message_point_reset_time ?? "n/a"}</span>
</div>
</div>
<div className="flex w-full max-w-[500px] flex-row items-center justify-between text-sm">
<span>订阅状态</span>
<div className="flex flex-row items-center space-x-2">
<span>{accountInfo?.subscription_active ? "活跃" : "无"}</span>
</div>
</div>
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"use client";

import { Icons } from "@/components/icons";
import { cn } from "@/lib/utils";
import { api } from "@/trpc/react";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";

export function PoekmonSharedInstanceUsageStatistics({
instanceId,
className,
}: {
instanceId: string;
className?: string;
}) {
const sumResult = api.resourceLog.sumPoekmonSharedResourceLogsInDurationWindowsByInstance.useQuery({
durationWindows: ["10m", "1h", "8h", "24h"],
instanceId,
});

const allLogsAreEmpty = sumResult.data?.every((item) => item.stats.count === 0);

return (
<div className={cn("flex flex-col", className)}>
<span className="text-md py-3 font-semibold">最近使用情况</span>
{!allLogsAreEmpty && (
<div className="flex flex-col space-y-2 text-sm">
{sumResult.data?.map((item) => (
<div key={item.durationWindow} className="flex w-full flex-row justify-between">
<div>Last {item.durationWindow}</div>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger>
<div className="flex flex-row space-x-2">
{/* <span>{item.stats.userCount}</span>
<span>{item.stats.count}</span>
<span>{item.stats.sumUtf8Length ?? 0}</span> */}
<div className="flex flex-row items-center">
{" "}
<Icons.user className="mr-2 h-4 w-4" /> {item.stats.userCount}
</div>
<div className="flex flex-row items-center">
{" "}
<Icons.message className="mr-2 h-4 w-4" /> {item.stats.count}
</div>
<div className="flex flex-row items-center">
{" "}
<Icons.fileBarChart className="mr-2 h-4 w-4" />
{item.stats.sumPoints}
</div>
</div>
</TooltipTrigger>
<TooltipContent side="left">
<p>
最近 {item.durationWindow}{item.stats.userCount} 用户使用,请求 {item.stats.count} 次,消耗{" "}
{item.stats.sumPoints} 积分点数
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
))}
</div>
)}
{allLogsAreEmpty && (
<div className="mx-auto flex h-[80px] w-full flex-row items-center justify-center align-middle">
<span className="text-sm text-muted-foreground">No statistics available</span>
</div>
)}
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -346,17 +346,33 @@ export const extendRouter = (router: Router) => {
...data,
} as PoekmonSharedResourceUsageLogDetails;

await db
.insert(resourceUsageLogs)
.values({
await db.transaction(async (tx) => {
await tx.insert(resourceUsageLogs).values({
id: createCUID(),
userId: data.user_id,
instanceId: c.var.instanceId,
type: ServiceTypeSchema.Values.POEKMON_SHARED,
details: logDetail,
createdAt: new Date(),
})
.returning();
});

if (logDetail.status === "success") {
const instance = await tx.query.serviceInstances.findFirst({
where: eq(serviceInstances.id, c.var.instanceId),
});
const instanceData = instance!.data as PoekmonSharedInstanceData;
if (instanceData.poe_account.account_info !== null) {
instanceData.poe_account.account_info.message_point_balance -= logDetail.consume_point;
}
await tx
.update(serviceInstances)
.set({
data: instanceData,
})
.where(eq(serviceInstances.id, c.var.instanceId));
}
});

return c.json(ok());
});

Expand Down
43 changes: 19 additions & 24 deletions src/schema/service/poekmon-shared.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,33 @@ import { z } from "zod";
import { createSelectSchema } from "drizzle-zod";
import { resourceUsageLogs } from "@/server/db/schema";

export const PoekmonSharedAccountInfoSchema = z.object({
account_email: z.string(),
subscription_active: z.boolean(),
subscription_plan_type: z.string().nullable(),
subscription_expires_time: z.number().int().nullable(),
message_point_balance: z.number().int(),
message_point_alloment: z.number().int(),
message_point_reset_time: z.number().int(),
});

export const PoekmonSharedAccountInfoUserReadableSchema = PoekmonSharedAccountInfoSchema.omit({
account_email: true,
subscription_plan_type: true,
subscription_expires_time: true,
});

export const PoekmonSharedAccountSchema = z.object({
status: z.enum(["active", "inactive", "initialized"]),
account_email: z.string().nullable(),
account_info: z
.object({
subscription_active: z.boolean(),
subscription_plan_type: z.string(),
subscription_expires_time: z.number().int(),
message_point_balance: z.number().int(),
message_point_alloment: z.number().int(),
message_point_reset_time: z.number().int(),
})
.nullable(),
account_info: PoekmonSharedAccountInfoSchema.nullable(),
account_info_dirty: z.boolean(),
});
export type PoekmonSharedAccount = z.infer<typeof PoekmonSharedAccountSchema>;

export const defaultPoekmonSharedAccount = (): PoekmonSharedAccount => ({
status: "initialized",
account_email: null,
account_info: null,
account_info_dirty: false,
});

export const PoekmonSharedInstanceDataSchema = z.object({
Expand Down Expand Up @@ -62,18 +69,6 @@ export const PoekmonSharedResourceLogSumResultSchema = z.object({
});
export type PoekmonSharedResourceLogSumResult = z.infer<typeof PoekmonSharedResourceLogSumResultSchema>;

export const PoekmonSharedLogGroupbyModelResultSchema = z.object({
durationWindow: DurationWindowSchema,
groups: z.array(
z.object({
model: z.string(),
count: z.number().int(),
sumTotalPoints: z.number().int(),
}),
),
});
export type PoekmonSharedLogGroupbyModelResult = z.infer<typeof PoekmonSharedLogGroupbyModelResultSchema>;

export const PoekmonSharedResourceUsageLogSchema = createSelectSchema(resourceUsageLogs).merge(
z.object({
details: PoekmonSharedResourceUsageLogDetailsSchema,
Expand Down
Loading

0 comments on commit 5937f58

Please sign in to comment.