feat(models): 统一模型规格价格与路由

This commit is contained in:
kinoko
2026-08-22 17:00:08 +08:00
parent d268a938e5
commit 236b850177
36 changed files with 3404 additions and 421 deletions

View File

@@ -31,12 +31,25 @@ export type PublicLogicalModel = {
inputPriceMicrocredits: number;
outputPriceMicrocredits: number;
cachedPriceMicrocredits: number;
priceTiers: PublicLogicalModelPriceTier[];
legacyModelIds: string[];
capabilitySpec: CapabilitySpec;
capabilityProfiles: CapabilitySpec[];
defaultOptions: Record<string, unknown>;
available: boolean;
};
export type PublicLogicalModelPriceTier = {
selector: Record<string, string>;
resolution: string;
videoSeconds: number;
billingMode: "fixed_request" | "per_second" | "token";
unitPriceMicrocredits: number;
inputTokenPriceMicrocredits: number;
outputTokenPriceMicrocredits: number;
cachedTokenPriceMicrocredits: number;
};
export type AdminLogicalRoute = {
id: string;
channelModelId: string;
@@ -73,6 +86,7 @@ export type LogicalModelMutation = {
inputPriceMicrocredits: number;
outputPriceMicrocredits: number;
cachedPriceMicrocredits: number;
legacyModelIds?: string[];
capabilitySpec: CapabilitySpec;
defaultOptions: Record<string, unknown>;
routes: Array<{ channelModelId: string; enabled: boolean; priority: number; weight: number }>;
@@ -83,6 +97,14 @@ export type RouteSimulationResult = {
candidates: Array<{ routeId: string; channelModelId: string; channelModelKey: string; channelModelName: string; priority: number; weight: number; enabled: boolean; matched: boolean; blocked: boolean; inPool: boolean; reasons?: string[] }>;
};
export type LogicalModelQuote = {
logicalModelId: string;
billingMode: PublicLogicalModel["billingMode"];
quantity: number;
amountMicrocredits: number;
estimated: boolean;
};
export function listLogicalModels() {
return request<{ models: PublicLogicalModel[] }>(apiClient.get("/models"));
}
@@ -91,6 +113,10 @@ export function listAvailableLogicalModels(intent: ModelRequestIntent) {
return request<{ models: PublicLogicalModel[] }>(apiClient.post("/models/available", intent));
}
export function quoteLogicalModel(id: string, intent: ModelRequestIntent, signal?: AbortSignal) {
return request<{ quote: LogicalModelQuote }>(apiClient.post(`/models/${encodeURIComponent(id)}/quote`, intent, { signal }));
}
export function listAdminLogicalModels() {
return request<{ models: AdminLogicalModel[] }>(apiClient.get("/admin/logical-models"));
}

View File

@@ -50,6 +50,7 @@ export type ChannelModel = {
id: string;
channelId: string;
modelKey: string;
providerModelKey: string;
displayName: string;
capability: "text" | "image" | "video" | "audio" | "";
protocol?: import("@/lib/model-protocols").ModelProtocol;
@@ -63,10 +64,49 @@ export type ChannelModel = {
priceVersion: number;
capabilityVersion?: number;
capabilityConfig?: import("@/lib/model-capabilities").ModelCapabilityConfig;
priceTiers: ChannelModelPriceTier[];
createdAt: string;
updatedAt: string;
};
export type ChannelModelPriceTier = {
id: string;
channelModelId: string;
selector: Record<string, string>;
selectorKey: string;
resolution: string;
videoSeconds: number;
providerModelKey: string;
billingMode: "fixed_request" | "per_second" | "token";
unitPriceMicrocredits: number;
inputTokenPriceMicrocredits: number;
outputTokenPriceMicrocredits: number;
cachedTokenPriceMicrocredits: number;
priceConfigured: boolean;
enabled: boolean;
priceVersion: number;
createdAt: string;
updatedAt: string;
};
// 系统渠道模型的写入合同。标量价格只用于兼容旧管理请求;新的后台界面只提交 priceTiers。
export type ChannelModelMutation = {
modelKey: string;
providerModelKey?: string;
displayName?: string;
capability: ChannelModel["capability"];
protocol?: ChannelModel["protocol"];
enabled?: boolean;
capabilityConfig?: ChannelModel["capabilityConfig"];
priceTiers?: Array<Omit<ChannelModelPriceTier, "id" | "channelModelId" | "selectorKey" | "priceVersion" | "createdAt" | "updatedAt">>;
billingMode?: ChannelModel["billingMode"];
unitPriceMicrocredits?: number;
inputTokenPriceMicrocredits?: number;
outputTokenPriceMicrocredits?: number;
cachedTokenPriceMicrocredits?: number;
priceConfigured?: boolean;
};
export type LinuxDOSetting = {
enabled: boolean;
clientId: string;
@@ -230,15 +270,15 @@ export function fetchAdminChannelModels(channelId: string) {
return request<{ models: string[]; added: number }>(api.post(`/admin/channels/${encodeURIComponent(channelId)}/models/fetch`));
}
export function testAdminChannelModel(channelId: string, input: Pick<ChannelModel, "modelKey" | "capability" | "protocol"> & { capabilityConfig?: ChannelModel["capabilityConfig"] }) {
export function testAdminChannelModel(channelId: string, input: Pick<ChannelModel, "modelKey" | "providerModelKey" | "capability" | "protocol"> & { capabilityConfig?: ChannelModel["capabilityConfig"] }) {
return request<{ durationMs: number }>(api.post(`/admin/channels/${encodeURIComponent(channelId)}/models/test`, input, { timeout: 10 * 60 * 1000 }));
}
export function createAdminChannelModel(channelId: string, input: Omit<ChannelModel, "id" | "channelId" | "priceVersion" | "createdAt" | "updatedAt">) {
export function createAdminChannelModel(channelId: string, input: ChannelModelMutation) {
return request<{ model: ChannelModel }>(api.post(`/admin/channels/${encodeURIComponent(channelId)}/models`, input));
}
export function updateAdminChannelModel(channelId: string, id: string, input: Omit<ChannelModel, "id" | "channelId" | "priceVersion" | "createdAt" | "updatedAt">) {
export function updateAdminChannelModel(channelId: string, id: string, input: ChannelModelMutation) {
return request<{ model: ChannelModel }>(api.patch(`/admin/channels/${encodeURIComponent(channelId)}/models/${encodeURIComponent(id)}`, input));
}