This commit is contained in:
张成
2025-12-27 20:14:40 +08:00
parent 43382668a3
commit 43f7884e52
14 changed files with 1818 additions and 21 deletions

View File

@@ -0,0 +1,317 @@
/**
* AI调用记录管理API - 后台管理
* 提供AI调用记录的查询和统计功能
*/
const Framework = require("../../framework/node-core-framework.js");
module.exports = {
/**
* @swagger
* /admin_api/ai_call_records/list:
* post:
* summary: 获取AI调用记录列表
* description: 分页获取所有AI调用记录
* tags: [后台-AI调用记录管理]
*/
'POST /ai_call_records/list': async (ctx) => {
try {
const models = Framework.getModels();
const { ai_call_records, op } = models;
const body = ctx.getBody();
// 获取分页参数
const { limit, offset } = ctx.getPageSize();
// 构建查询条件
const where = { is_delete: 0 };
// 搜索条件
if (body.seachOption) {
const { key, value, status, service_type, model_name, api_provider, business_type, user_id, sn_code } = body.seachOption;
// 关键字搜索
if (value && key) {
if (key === 'user_id' || key === 'reference_id') {
where[key] = value;
} else if (key === 'sn_code') {
where.sn_code = { [op.like]: `%${value}%` };
}
}
// 状态筛选
if (status) {
where.status = status;
}
// 服务类型筛选
if (service_type) {
where.service_type = service_type;
}
// 模型名称筛选
if (model_name) {
where.model_name = model_name;
}
// API提供商筛选
if (api_provider) {
where.api_provider = api_provider;
}
// 业务类型筛选
if (business_type) {
where.business_type = business_type;
}
// 用户ID筛选
if (user_id) {
where.user_id = user_id;
}
// 设备序列号筛选
if (sn_code) {
where.sn_code = sn_code;
}
// 日期范围筛选
if (body.seachOption.start_date && body.seachOption.end_date) {
where.create_time = {
[op.between]: [new Date(body.seachOption.start_date), new Date(body.seachOption.end_date)]
};
}
}
const result = await ai_call_records.findAndCountAll({
where,
limit,
offset,
order: [['create_time', 'DESC'], ['id', 'DESC']],
attributes: [
'id', 'user_id', 'sn_code', 'service_type', 'model_name',
'prompt_tokens', 'completion_tokens', 'total_tokens',
'cost_amount', 'status', 'response_time', 'api_provider',
'business_type', 'reference_id', 'create_time'
]
});
return ctx.success(result);
} catch (error) {
console.error('获取AI调用记录列表失败:', error);
return ctx.fail('获取AI调用记录列表失败: ' + error.message);
}
},
/**
* @swagger
* /admin_api/ai_call_records/detail:
* get:
* summary: 获取AI调用记录详情
* description: 根据ID获取AI调用记录详细信息包含请求和响应内容
* tags: [后台-AI调用记录管理]
*/
'GET /ai_call_records/detail': async (ctx) => {
try {
const models = Framework.getModels();
const { ai_call_records } = models;
const { id } = ctx.getQuery();
if (!id) {
return ctx.fail('记录ID不能为空');
}
const record = await ai_call_records.findOne({
where: { id, is_delete: 0 }
});
if (!record) {
return ctx.fail('记录不存在');
}
return ctx.success(record);
} catch (error) {
console.error('获取AI调用记录详情失败:', error);
return ctx.fail('获取AI调用记录详情失败: ' + error.message);
}
},
/**
* @swagger
* /admin_api/ai_call_records/stats:
* post:
* summary: 获取AI调用统计数据
* description: 统计Token使用量、调用次数、费用等
* tags: [后台-AI调用记录管理]
*/
'POST /ai_call_records/stats': async (ctx) => {
try {
const models = Framework.getModels();
const { ai_call_records, op } = models;
const body = ctx.getBody();
const where = { is_delete: 0, status: 'success' };
// 构建查询条件
if (body.user_id) {
where.user_id = body.user_id;
}
if (body.sn_code) {
where.sn_code = body.sn_code;
}
if (body.business_type) {
where.business_type = body.business_type;
}
if (body.start_date && body.end_date) {
where.create_time = {
[op.between]: [new Date(body.start_date), new Date(body.end_date)]
};
}
const records = await ai_call_records.findAll({ where });
// 计算统计数据
const stats = {
total_calls: records.length,
total_prompt_tokens: 0,
total_completion_tokens: 0,
total_tokens: 0,
total_cost: 0,
avg_response_time: 0,
by_model: {},
by_service_type: {},
by_status: { success: 0, failed: 0, timeout: 0 }
};
let totalResponseTime = 0;
let responseTimeCount = 0;
records.forEach(record => {
// Token统计
stats.total_prompt_tokens += record.prompt_tokens || 0;
stats.total_completion_tokens += record.completion_tokens || 0;
stats.total_tokens += record.total_tokens || 0;
stats.total_cost += parseFloat(record.cost_amount || 0);
// 响应时间统计
if (record.response_time) {
totalResponseTime += record.response_time;
responseTimeCount++;
}
// 按模型统计
if (!stats.by_model[record.model_name]) {
stats.by_model[record.model_name] = {
count: 0,
total_tokens: 0,
total_cost: 0
};
}
stats.by_model[record.model_name].count++;
stats.by_model[record.model_name].total_tokens += record.total_tokens || 0;
stats.by_model[record.model_name].total_cost += parseFloat(record.cost_amount || 0);
// 按服务类型统计
if (!stats.by_service_type[record.service_type]) {
stats.by_service_type[record.service_type] = {
count: 0,
total_tokens: 0
};
}
stats.by_service_type[record.service_type].count++;
stats.by_service_type[record.service_type].total_tokens += record.total_tokens || 0;
});
// 计算平均响应时间
if (responseTimeCount > 0) {
stats.avg_response_time = Math.round(totalResponseTime / responseTimeCount);
}
// 查询失败和超时的记录
const failedCount = await ai_call_records.count({
where: { ...where, status: 'failed', is_delete: 0 }
});
const timeoutCount = await ai_call_records.count({
where: { ...where, status: 'timeout', is_delete: 0 }
});
stats.by_status.success = records.length;
stats.by_status.failed = failedCount;
stats.by_status.timeout = timeoutCount;
return ctx.success(stats);
} catch (error) {
console.error('获取AI调用统计失败:', error);
return ctx.fail('获取AI调用统计失败: ' + error.message);
}
},
/**
* @swagger
* /admin_api/ai_call_records/delete:
* post:
* summary: 删除AI调用记录
* description: 软删除指定的AI调用记录
* tags: [后台-AI调用记录管理]
*/
'POST /ai_call_records/delete': async (ctx) => {
try {
const models = Framework.getModels();
const { ai_call_records } = models;
const { id } = ctx.getBody();
if (!id) {
return ctx.fail('记录ID不能为空');
}
const record = await ai_call_records.findOne({
where: { id, is_delete: 0 }
});
if (!record) {
return ctx.fail('记录不存在');
}
// 软删除
await ai_call_records.update(
{ is_delete: 1 },
{ where: { id } }
);
return ctx.success({ message: 'AI调用记录删除成功' });
} catch (error) {
console.error('删除AI调用记录失败:', error);
return ctx.fail('删除AI调用记录失败: ' + error.message);
}
},
/**
* @swagger
* /admin_api/ai_call_records/batch_delete:
* post:
* summary: 批量删除AI调用记录
* description: 批量软删除AI调用记录
* tags: [后台-AI调用记录管理]
*/
'POST /ai_call_records/batch_delete': async (ctx) => {
try {
const models = Framework.getModels();
const { ai_call_records, op } = models;
const { ids } = ctx.getBody();
if (!ids || !Array.isArray(ids) || ids.length === 0) {
return ctx.fail('记录ID列表不能为空');
}
// 批量软删除
await ai_call_records.update(
{ is_delete: 1 },
{ where: { id: { [op.in]: ids } } }
);
return ctx.success({ message: `成功删除 ${ids.length} 条记录` });
} catch (error) {
console.error('批量删除AI调用记录失败:', error);
return ctx.fail('批量删除AI调用记录失败: ' + error.message);
}
}
};