visual-journal / src /lib /cost-utils.ts
gpt-image-playground deploy
Deploy 17eadcc to Docker Space
96bdf6c
Raw
History Blame Contribute Delete
5.69 kB
type ApiUsage = {
input_tokens_details?: {
text_tokens?: number;
image_tokens?: number;
};
output_tokens?: number;
};
export type CostDetails = {
estimated_cost_usd: number;
text_input_tokens: number;
image_input_tokens: number;
image_output_tokens: number;
};
// gpt-image-1 价格。
const GPT_IMAGE_1_TEXT_INPUT_COST_PER_TOKEN = 0.000005; // $5.00/1M
const GPT_IMAGE_1_IMAGE_INPUT_COST_PER_TOKEN = 0.00001; // $10.00/1M
const GPT_IMAGE_1_IMAGE_OUTPUT_COST_PER_TOKEN = 0.00004; // $40.00/1M
// gpt-image-1-mini 价格。
const GPT_IMAGE_1_MINI_TEXT_INPUT_COST_PER_TOKEN = 0.000002; // $2.00/1M
const GPT_IMAGE_1_MINI_IMAGE_INPUT_COST_PER_TOKEN = 0.0000025; // $2.50/1M
const GPT_IMAGE_1_MINI_IMAGE_OUTPUT_COST_PER_TOKEN = 0.000008; // $8.00/1M
// gpt-image-1.5 价格。
const GPT_IMAGE_1_5_TEXT_INPUT_COST_PER_TOKEN = 0.000005; // $5.00/1M
const GPT_IMAGE_1_5_IMAGE_INPUT_COST_PER_TOKEN = 0.000008; // $8.00/1M
const GPT_IMAGE_1_5_IMAGE_OUTPUT_COST_PER_TOKEN = 0.000032; // $32.00/1M
// gpt-image-2 价格。
const GPT_IMAGE_2_TEXT_INPUT_COST_PER_TOKEN = 0.000005; // $5.00/1M
const GPT_IMAGE_2_IMAGE_INPUT_COST_PER_TOKEN = 0.000008; // $8.00/1M
const GPT_IMAGE_2_IMAGE_OUTPUT_COST_PER_TOKEN = 0.00003; // $30.00/1M
export type GptImageModel = 'gpt-image-1' | 'gpt-image-1-mini' | 'gpt-image-1.5' | 'gpt-image-2';
export type ModelRates = {
textInputPerToken: number;
imageInputPerToken: number;
imageOutputPerToken: number;
textInputPerMillion: number;
imageInputPerMillion: number;
imageOutputPerMillion: number;
};
export function getModelRates(model: GptImageModel): ModelRates {
if (model === 'gpt-image-1-mini') {
return {
textInputPerToken: GPT_IMAGE_1_MINI_TEXT_INPUT_COST_PER_TOKEN,
imageInputPerToken: GPT_IMAGE_1_MINI_IMAGE_INPUT_COST_PER_TOKEN,
imageOutputPerToken: GPT_IMAGE_1_MINI_IMAGE_OUTPUT_COST_PER_TOKEN,
textInputPerMillion: 2,
imageInputPerMillion: 2.5,
imageOutputPerMillion: 8
};
}
if (model === 'gpt-image-1.5') {
return {
textInputPerToken: GPT_IMAGE_1_5_TEXT_INPUT_COST_PER_TOKEN,
imageInputPerToken: GPT_IMAGE_1_5_IMAGE_INPUT_COST_PER_TOKEN,
imageOutputPerToken: GPT_IMAGE_1_5_IMAGE_OUTPUT_COST_PER_TOKEN,
textInputPerMillion: 5,
imageInputPerMillion: 8,
imageOutputPerMillion: 32
};
}
if (model === 'gpt-image-2') {
return {
textInputPerToken: GPT_IMAGE_2_TEXT_INPUT_COST_PER_TOKEN,
imageInputPerToken: GPT_IMAGE_2_IMAGE_INPUT_COST_PER_TOKEN,
imageOutputPerToken: GPT_IMAGE_2_IMAGE_OUTPUT_COST_PER_TOKEN,
textInputPerMillion: 5,
imageInputPerMillion: 8,
imageOutputPerMillion: 30
};
}
return {
textInputPerToken: GPT_IMAGE_1_TEXT_INPUT_COST_PER_TOKEN,
imageInputPerToken: GPT_IMAGE_1_IMAGE_INPUT_COST_PER_TOKEN,
imageOutputPerToken: GPT_IMAGE_1_IMAGE_OUTPUT_COST_PER_TOKEN,
textInputPerMillion: 5,
imageInputPerMillion: 10,
imageOutputPerMillion: 40
};
}
/**
* 根据 token 用量估算 GPT 图片模型 API 调用成本。
* @param usage OpenAI API 响应中的 usage 对象。
* @param model 使用的模型。
* @returns CostDetails 对象;usage 数据无效时返回 null。
*/
export function calculateApiCost(
usage: ApiUsage | undefined | null,
model: GptImageModel = 'gpt-image-2'
): CostDetails | null {
if (!usage || !usage.input_tokens_details || usage.output_tokens === undefined || usage.output_tokens === null) {
console.warn('费用计算缺少有效 usage 数据:', usage);
return null;
}
const textInT = usage.input_tokens_details.text_tokens ?? 0;
const imgInT = usage.input_tokens_details.image_tokens ?? 0;
const imgOutT = usage.output_tokens ?? 0;
// 校验 token 类型。
if (typeof textInT !== 'number' || typeof imgInT !== 'number' || typeof imgOutT !== 'number') {
console.error('usage 数据中的 token 类型无效:', usage);
return null;
}
// 按模型选择价格。
let textInputCost: number;
let imageInputCost: number;
let imageOutputCost: number;
if (model === 'gpt-image-1-mini') {
textInputCost = GPT_IMAGE_1_MINI_TEXT_INPUT_COST_PER_TOKEN;
imageInputCost = GPT_IMAGE_1_MINI_IMAGE_INPUT_COST_PER_TOKEN;
imageOutputCost = GPT_IMAGE_1_MINI_IMAGE_OUTPUT_COST_PER_TOKEN;
} else if (model === 'gpt-image-1.5') {
textInputCost = GPT_IMAGE_1_5_TEXT_INPUT_COST_PER_TOKEN;
imageInputCost = GPT_IMAGE_1_5_IMAGE_INPUT_COST_PER_TOKEN;
imageOutputCost = GPT_IMAGE_1_5_IMAGE_OUTPUT_COST_PER_TOKEN;
} else if (model === 'gpt-image-2') {
textInputCost = GPT_IMAGE_2_TEXT_INPUT_COST_PER_TOKEN;
imageInputCost = GPT_IMAGE_2_IMAGE_INPUT_COST_PER_TOKEN;
imageOutputCost = GPT_IMAGE_2_IMAGE_OUTPUT_COST_PER_TOKEN;
} else {
// 默认按 gpt-image-1 计价。
textInputCost = GPT_IMAGE_1_TEXT_INPUT_COST_PER_TOKEN;
imageInputCost = GPT_IMAGE_1_IMAGE_INPUT_COST_PER_TOKEN;
imageOutputCost = GPT_IMAGE_1_IMAGE_OUTPUT_COST_PER_TOKEN;
}
const costUSD = textInT * textInputCost + imgInT * imageInputCost + imgOutT * imageOutputCost;
// 保留 4 位小数。
const costRounded = Math.round(costUSD * 10000) / 10000;
return {
estimated_cost_usd: costRounded,
text_input_tokens: textInT,
image_input_tokens: imgInT,
image_output_tokens: imgOutT
};
}