码桶
发现社区成员的开源项目
index.js3.6 KB
/**
* 智能计算器插件(测试用)
* - 对接智能助手:声明 aiTools.calculator,AI 在对话中遇到数学计算会自动调用
* - 文本指令:「计算 1+2*3」或「calc 1+2*3」
*/
let PRECISION = 2; // 默认小数位,可被插件设置覆盖
// 尝试读取该机器人在「插件设置」里配置的精度(plugin_id 取 meta.id)
async function loadPrecision(botId) {
try {
const db = require('../../../lib/db');
const r = await db.row(
'SELECT data FROM plugin_settings WHERE plugin_id=? AND bot_id=? LIMIT 1',
['calc', botId || 0]
);
if (r && r.data) {
const obj = JSON.parse(r.data);
if (obj && typeof obj.precision === 'number') PRECISION = obj.precision;
}
} catch (_) {
/* 读取失败则用默认精度,不影响计算 */
}
}
// 安全计算:仅允许数字与基本运算符,避免 eval 注入
function safeCalc(expr) {
if (!expr) return { error: '表达式为空' };
if (!/^[0-9+\-*/%.\s]+$/.test(expr)) return { error: '仅支持数字与 + - * / % ( ) 运算' };
try {
// eslint-disable-next-line no-new-func
const v = Function('"use strict"; return (' + expr + ')')();
if (typeof v !== 'number' || !isFinite(v)) return { error: '表达式无效或结果非数值' };
const f = Math.pow(10, Math.min(10, Math.max(0, PRECISION | 0)));
return { value: Math.round(v * f) / f };
} catch (e) {
return { error: '计算错误:' + e.message };
}
}
module.exports = {
meta: {
id: 'calc',
name: '智能计算器',
version: '1.0.0',
author: 'test',
category: '实用工具',
description: '对接智能助手的计算器:在对话里让 AI 帮你算账/算数时会自动调用;也支持「计算 1+2*3」文本指令。',
usage: '「计算 1+2*3」或在对聊中让 AI 计算',
entry: 'index.js',
configurable: true,
settingsSchema: [
{ key: 'precision', label: '小数位数', type: 'number', placeholder: '2', help: '计算结果保留的小数位数(0-10)' }
],
aiTools: [
{
type: 'function',
function: {
name: 'calculator',
description: '计算一个数学表达式,支持 + - * / % 和括号。当用户需要算账、算数、比较数值时使用。',
parameters: {
type: 'object',
properties: {
expression: { type: 'string', description: '要计算的数学表达式,例如 "1+2*3" 或 "(100-30)/7"' }
},
required: ['expression']
}
}
}
]
},
// 供智能助手(function calling)调用
async handleAiTool(name, args, ctx) {
if (name !== 'calculator') return '未知工具:' + name;
if (ctx && ctx.bot && ctx.bot.id) {
try { await loadPrecision(ctx.bot.id); } catch (_) {}
}
const expr = String(args.expression || '').trim();
const r = safeCalc(expr);
if (r.error) return '计算失败:' + r.error;
return `${expr} = ${r.value}`;
},
async onMessage(msg, ctx) {
const text = (msg.content || '').trim();
if (text.startsWith('计算 ') || /^calc\s/i.test(text)) {
if (ctx && ctx.bot && ctx.bot.id) {
try { await loadPrecision(ctx.bot.id); } catch (_) {}
}
const expr = text.slice(text.indexOf(' ') + 1).trim();
const r = safeCalc(expr);
if (r.error) {
await ctx.sendText('⚠️ ' + r.error);
return true;
}
await ctx.sendText(`🧮 ${expr} = ${r.value}`);
return true;
}
return false;
}
};