ai-chatbot/lib/points/config.ts
2026-04-05 21:54:11 +08:00

105 lines
2.8 KiB
TypeScript

export const POINTS_SYSTEM_CONFIG_KEY = "points_system_config";
export const POINTS_PACKAGES_KEY = "points_packages";
export type PointsSystemConfig = {
enabled: boolean;
blockOnInsufficient: boolean;
creditCostPer3DModel: number;
creditCostPer3DWorld: number;
};
export type PointsPackage = {
id: string;
name: string;
points: number;
price: number;
currency: string;
isEnabled: boolean;
};
export const defaultPointsSystemConfig: PointsSystemConfig = {
enabled: false,
blockOnInsufficient: true,
creditCostPer3DModel: 0,
creditCostPer3DWorld: 0,
};
export const defaultPointsPackages: PointsPackage[] = [
{
id: "starter-1000",
name: "入门包",
points: 1000,
price: 9.9,
currency: "CNY",
isEnabled: true,
},
{
id: "pro-5000",
name: "专业包",
points: 5000,
price: 39.9,
currency: "CNY",
isEnabled: true,
},
];
export function normalizePointsSystemConfig(value: unknown): PointsSystemConfig {
if (!value || typeof value !== "object") {
return defaultPointsSystemConfig;
}
const raw = value as Partial<PointsSystemConfig> & {
creditCostPer3D?: number;
};
const normalizeCost = (input: unknown) => {
const parsedValue = Number(input);
return Number.isFinite(parsedValue) && parsedValue > 0
? Math.min(100000, Math.round(parsedValue))
: 0;
};
const legacy3DCost = normalizeCost(raw.creditCostPer3D);
return {
enabled: raw.enabled === true,
blockOnInsufficient: raw.blockOnInsufficient !== false,
creditCostPer3DModel: normalizeCost(
raw.creditCostPer3DModel ?? legacy3DCost
),
creditCostPer3DWorld: normalizeCost(
raw.creditCostPer3DWorld ?? legacy3DCost
),
};
}
export function normalizePointsPackages(value: unknown): PointsPackage[] {
if (!Array.isArray(value)) {
return defaultPointsPackages;
}
const normalized = value
.map((item, index) => {
if (!item || typeof item !== "object") return null;
const raw = item as Partial<PointsPackage>;
const id = String(raw.id || `package-${index + 1}`).trim();
const name = String(raw.name || "").trim();
const points = Number(raw.points);
const price = Number(raw.price);
const currency = String(raw.currency || "CNY").trim().toUpperCase();
if (!id || !name || !Number.isFinite(points) || points <= 0) return null;
if (!Number.isFinite(price) || price < 0) return null;
return {
id: id.slice(0, 64),
name: name.slice(0, 64),
points: Math.round(points),
price: Number(price.toFixed(2)),
currency: currency.slice(0, 8) || "CNY",
isEnabled: raw.isEnabled !== false,
} satisfies PointsPackage;
})
.filter((item): item is PointsPackage => Boolean(item))
.slice(0, 30);
return normalized.length > 0 ? normalized : defaultPointsPackages;
}