169 lines
6.7 KiB
JavaScript
169 lines
6.7 KiB
JavaScript
const Framework = require('../../framework/node-core-framework');
|
||
|
||
/**
|
||
* AI调用记录服务
|
||
* 负责记录所有AI API调用的详细信息
|
||
*/
|
||
class AiCallRecorder {
|
||
/**
|
||
* 记录AI调用
|
||
* @param {Object} params - 调用参数
|
||
* @param {Number} params.user_id - 用户ID
|
||
* @param {String} params.sn_code - 设备SN码
|
||
* @param {String} params.service_type - 服务类型(chat/completion/embedding)
|
||
* @param {String} params.model_name - 模型名称
|
||
* @param {Number} params.prompt_tokens - 输入Token数
|
||
* @param {Number} params.completion_tokens - 输出Token数
|
||
* @param {Number} params.total_tokens - 总Token数
|
||
* @param {String} params.request_content - 请求内容
|
||
* @param {String} params.response_content - 响应内容
|
||
* @param {Number} params.cost_amount - 费用(元)
|
||
* @param {String} params.status - 状态(success/failed)
|
||
* @param {String} params.error_message - 错误信息
|
||
* @param {Number} params.response_time - 响应时间(毫秒)
|
||
* @param {String} params.api_provider - API提供商
|
||
* @param {String} params.business_type - 业务类型
|
||
* @param {String} params.reference_id - 关联业务ID
|
||
* @returns {Promise<Object>} 记录结果
|
||
*/
|
||
static async record(params) {
|
||
try {
|
||
const models = Framework.getModels();
|
||
const { ai_call_records } = models;
|
||
|
||
if (!ai_call_records) {
|
||
console.warn('[AI记录] ai_call_records 模型未加载');
|
||
return null;
|
||
}
|
||
|
||
const now = new Date();
|
||
const record = await ai_call_records.create({
|
||
user_id: params.user_id || null,
|
||
sn_code: params.sn_code || null,
|
||
service_type: params.service_type,
|
||
model_name: params.model_name,
|
||
prompt_tokens: params.prompt_tokens || 0,
|
||
completion_tokens: params.completion_tokens || 0,
|
||
total_tokens: params.total_tokens || 0,
|
||
request_content: params.request_content || null,
|
||
response_content: params.response_content || null,
|
||
cost_amount: params.cost_amount || null,
|
||
status: params.status || 'success',
|
||
error_message: params.error_message || null,
|
||
response_time: params.response_time || null,
|
||
api_provider: params.api_provider || 'qwen',
|
||
business_type: params.business_type || null,
|
||
reference_id: params.reference_id || null,
|
||
create_time: now,
|
||
last_modify_time: now,
|
||
is_delete: 0
|
||
});
|
||
|
||
return record;
|
||
} catch (error) {
|
||
console.error('[AI记录] 记录失败:', error.message);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取用户Token使用统计
|
||
* @param {Number} userId - 用户ID
|
||
* @param {Object} options - 查询选项
|
||
* @param {Date} options.startDate - 开始日期
|
||
* @param {Date} options.endDate - 结束日期
|
||
* @returns {Promise<Object>} 统计数据
|
||
*/
|
||
static async getUserTokenStats(userId, options = {}) {
|
||
try {
|
||
const models = Framework.getModels();
|
||
const { ai_call_records } = models;
|
||
const { Op } = Framework.getSequelize();
|
||
|
||
if (!ai_call_records) {
|
||
return null;
|
||
}
|
||
|
||
const where = {
|
||
user_id: userId,
|
||
is_delete: 0
|
||
};
|
||
|
||
if (options.startDate && options.endDate) {
|
||
where.create_time = {
|
||
[Op.between]: [options.startDate, options.endDate]
|
||
};
|
||
}
|
||
|
||
const stats = await ai_call_records.findOne({
|
||
where,
|
||
attributes: [
|
||
[Framework.getSequelize().fn('COUNT', Framework.getSequelize().col('id')), 'total_calls'],
|
||
[Framework.getSequelize().fn('SUM', Framework.getSequelize().col('prompt_tokens')), 'total_prompt_tokens'],
|
||
[Framework.getSequelize().fn('SUM', Framework.getSequelize().col('completion_tokens')), 'total_completion_tokens'],
|
||
[Framework.getSequelize().fn('SUM', Framework.getSequelize().col('total_tokens')), 'total_tokens'],
|
||
[Framework.getSequelize().fn('SUM', Framework.getSequelize().col('cost_amount')), 'total_cost'],
|
||
[Framework.getSequelize().fn('AVG', Framework.getSequelize().col('response_time')), 'avg_response_time']
|
||
],
|
||
raw: true
|
||
});
|
||
|
||
return stats;
|
||
} catch (error) {
|
||
console.error('[AI记录] 获取用户统计失败:', error.message);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取设备Token使用统计
|
||
* @param {String} snCode - 设备SN码
|
||
* @param {Object} options - 查询选项
|
||
* @param {Date} options.startDate - 开始日期
|
||
* @param {Date} options.endDate - 结束日期
|
||
* @returns {Promise<Object>} 统计数据
|
||
*/
|
||
static async getDeviceTokenStats(snCode, options = {}) {
|
||
try {
|
||
const models = Framework.getModels();
|
||
const { ai_call_records } = models;
|
||
const { Op } = Framework.getSequelize();
|
||
|
||
if (!ai_call_records) {
|
||
return null;
|
||
}
|
||
|
||
const where = {
|
||
sn_code: snCode,
|
||
is_delete: 0
|
||
};
|
||
|
||
if (options.startDate && options.endDate) {
|
||
where.create_time = {
|
||
[Op.between]: [options.startDate, options.endDate]
|
||
};
|
||
}
|
||
|
||
const stats = await ai_call_records.findOne({
|
||
where,
|
||
attributes: [
|
||
[Framework.getSequelize().fn('COUNT', Framework.getSequelize().col('id')), 'total_calls'],
|
||
[Framework.getSequelize().fn('SUM', Framework.getSequelize().col('prompt_tokens')), 'total_prompt_tokens'],
|
||
[Framework.getSequelize().fn('SUM', Framework.getSequelize().col('completion_tokens')), 'total_completion_tokens'],
|
||
[Framework.getSequelize().fn('SUM', Framework.getSequelize().col('total_tokens')), 'total_tokens'],
|
||
[Framework.getSequelize().fn('SUM', Framework.getSequelize().col('cost_amount')), 'total_cost'],
|
||
[Framework.getSequelize().fn('AVG', Framework.getSequelize().col('response_time')), 'avg_response_time']
|
||
],
|
||
raw: true
|
||
});
|
||
|
||
return stats;
|
||
} catch (error) {
|
||
console.error('[AI记录] 获取设备统计失败:', error.message);
|
||
throw error;
|
||
}
|
||
}
|
||
}
|
||
|
||
module.exports = AiCallRecorder;
|