Files
autoAiWorkSys/api/services/ai_call_recorder.js
张成 68b4db0aee 1
2026-02-01 22:00:19 +08:00

169 lines
6.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const Framework = require('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;