1
This commit is contained in:
317
api/controller_admin/ai_call_records.js
Normal file
317
api/controller_admin/ai_call_records.js
Normal 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user