feat(pricing): 重构定价管理页面,支持卡片视图和多选筛选功能
- 更新定价模型,支持可选输入和输出字段 - 增加多选自动完成输入组件,允许按渠道、令牌和类型筛选 - 重新设计定价行的构建逻辑,优化数据处理 - 提升用户体验,支持 JSON 配置与卡片视图之间的切换 - 增强 API 端点,确保定价配置的有效性和一致性
This commit is contained in:
1 parent
f226f47545
commit
1c9bd91aed
5 files changed
+983
-442
No files matched your search
+65
-15
@@ -5,18 +5,72 @@ import { getJsonSetting, saveSetting } from "../utils";
|
||||
import { CONSTANTS } from "../constants";
|
||||
import { CommonErrorResponse, CommonSuccessfulResponse } from "../model";
|
||||
|
||||
const pricingModelSchema = z.object({
|
||||
input: z.number().optional(),
|
||||
output: z.number().optional(),
|
||||
cache: z.number().optional(),
|
||||
request: z.number().optional(),
|
||||
});
|
||||
|
||||
const toPositiveNumber = (value: unknown): number | undefined => {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return value > 0 ? value : undefined;
|
||||
};
|
||||
|
||||
const sanitizePricingConfig = (
|
||||
config: Record<string, Partial<ModelPricing>> | null | undefined
|
||||
): Record<string, Partial<ModelPricing>> => {
|
||||
if (!config || typeof config !== "object") {
|
||||
return {};
|
||||
}
|
||||
|
||||
const normalizedEntries: Array<[string, Partial<ModelPricing>]> = [];
|
||||
|
||||
Object.entries(config).forEach(([model, pricing]) => {
|
||||
const normalizedModel = model.trim();
|
||||
if (!normalizedModel || !pricing || typeof pricing !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
const normalizedPricing: Partial<ModelPricing> = {};
|
||||
const input = toPositiveNumber(pricing.input);
|
||||
const output = toPositiveNumber(pricing.output);
|
||||
const cache = toPositiveNumber(pricing.cache);
|
||||
const request = toPositiveNumber(pricing.request);
|
||||
|
||||
if (input !== undefined) {
|
||||
normalizedPricing.input = input;
|
||||
}
|
||||
if (output !== undefined) {
|
||||
normalizedPricing.output = output;
|
||||
}
|
||||
if (cache !== undefined) {
|
||||
normalizedPricing.cache = cache;
|
||||
}
|
||||
if (request !== undefined) {
|
||||
normalizedPricing.request = request;
|
||||
}
|
||||
|
||||
if (Object.keys(normalizedPricing).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
normalizedEntries.push([normalizedModel, normalizedPricing]);
|
||||
});
|
||||
|
||||
return Object.fromEntries(normalizedEntries);
|
||||
};
|
||||
|
||||
// Pricing 获取配置 API
|
||||
export class PricingGetEndpoint extends OpenAPIRoute {
|
||||
schema = {
|
||||
tags: ['Admin API'],
|
||||
summary: 'Get global pricing configuration',
|
||||
responses: {
|
||||
...CommonSuccessfulResponse(z.record(z.string(), z.object({
|
||||
input: z.number(),
|
||||
output: z.number(),
|
||||
cache: z.number().optional(),
|
||||
request: z.number().optional(),
|
||||
}))),
|
||||
...CommonSuccessfulResponse(z.record(z.string(), pricingModelSchema)),
|
||||
...CommonErrorResponse,
|
||||
},
|
||||
};
|
||||
@@ -29,7 +83,7 @@ export class PricingGetEndpoint extends OpenAPIRoute {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: pricingConfig || {}
|
||||
data: sanitizePricingConfig(pricingConfig)
|
||||
} as CommonResponse;
|
||||
}
|
||||
}
|
||||
@@ -43,12 +97,7 @@ export class PricingUpdateEndpoint extends OpenAPIRoute {
|
||||
body: {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: z.record(z.string(), z.object({
|
||||
input: z.number(),
|
||||
output: z.number(),
|
||||
cache: z.number().optional(),
|
||||
request: z.number().optional(),
|
||||
})),
|
||||
schema: z.record(z.string(), pricingModelSchema),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,12 +109,13 @@ export class PricingUpdateEndpoint extends OpenAPIRoute {
|
||||
};
|
||||
|
||||
async handle(c: Context<HonoCustomType>) {
|
||||
const body = await c.req.json<Record<string, ModelPricing>>();
|
||||
const body = await c.req.json<Record<string, Partial<ModelPricing>>>();
|
||||
const normalizedConfig = sanitizePricingConfig(body);
|
||||
|
||||
await saveSetting(
|
||||
c,
|
||||
CONSTANTS.MODEL_PRICING_KEY,
|
||||
JSON.stringify(body)
|
||||
JSON.stringify(normalizedConfig)
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
Reference in new issue
Block a user