内容大纲
实战完整示例
奶狗 发表于 4 周前 浏览 40 字数 2883 阅读时长 15分钟
6. 实战完整示例
6.1 示例 A:命令型插件(含配置 + 图片)
参考 plugins/aidraw/index.js,通过命令在 QQ/微信/网页端生成 AI 图片:
/**
* AI 绘图插件
* 命令入口:/draw /绘图 /imagine /生图
*/
const path = require('path');
const fs = require('fs');
const os = require('os');
const axios = require('axios');
const db = require('../../lib/db');
const settings = require('../../lib/settings');
const PLUGIN_ID = 'aidraw';
const PREFIXES = ['/draw', '/绘图', '/imagine', '/生图'];
async function getSetting(botId, key, fallback) {
const row = await db.row(
'SELECT config_value FROM plugin_settings WHERE bot_id=? AND plugin_id=? AND config_key=?',
[botId, PLUGIN_ID, key]
);
if (row && row.config_value != null && String(row.config_value).trim() !== '') return row.config_value;
return fallback;
}
async function loadConfig(botId) {
const apiBase = (await getSetting(botId, 'draw_api_base', await settings.getSetting('ai_image_gen_api_base', ''))).trim();
const apiKey = (await getSetting(botId, 'draw_api_key', await settings.getSetting('ai_image_gen_api_key', ''))).trim();
const model = (await getSetting(botId, 'draw_model', await settings.getSetting('ai_image_gen_model', ''))).trim();
const size = (await getSetting(botId, 'draw_size', await settings.getSetting('ai_image_gen_size', '1024x1024'))).trim();
return { apiBase, apiKey, model, size };
}
module.exports = {
meta: {
id: PLUGIN_ID,
name: 'AI 绘图',
version: '1.0.0',
author: '奶狗',
category: 'AI 创作',
description: '通过命令在 QQ/微信/网页端生成 AI 图片,支持自定义 OpenAI 兼容生图接口。',
entry: 'aidraw/index.js',
commandPrefix: PREFIXES,
configurable: true,
},
async onMessage(msg, ctx) {
const text = (msg.content || '').trim();
let prompt = null;
for (const p of PREFIXES) {
if (text === p) { prompt = ''; break; }
if (text.startsWith(p)) { prompt = text.slice(p.length).replace(/^[\s::]+/, '').trim(); break; }
}
if (prompt === null) return; // 非本插件命令,放行
const botId = (ctx.bot && ctx.bot.id) || 0;
if (/^(help|帮助|h)$/i.test(prompt)) { await ctx.sendText('发送 /draw 一只猫'); return true; }
if (!prompt) { await ctx.sendText('请输入提示词,如 /draw 一只猫'); return true; }
const cfg = await loadConfig(botId);
await ctx.sendText('🎨 正在生成:' + prompt);
try {
const url = cfg.apiBase.replace(/\/+$/, '') + '/v1/images/generations';
const resp = await axios.post(url, {
prompt, n: 1, size: cfg.size || '1024x1024', response_format: 'b64_json',
...(cfg.model ? { model: cfg.model } : {}),
}, { headers: { Authorization: 'Bearer ' + cfg.apiKey }, timeout: 120000 });
const img = (resp.data.data || [])[0];
const buf = img.b64_json ? Buffer.from(img.b64_json, 'base64')
: Buffer.from((await axios.get(img.url, { responseType: 'arraybuffer' })).data);
const fpath = path.join(os.tmpdir(), 'aidraw_' + Date.now() + '.png');
fs.writeFileSync(fpath, buf);
try { await ctx.sendMedia(fpath, 'image'); }
finally { try { fs.unlinkSync(fpath); } catch (_) {} }
} catch (e) {
await ctx.sendText('生成失败:' + e.message);
}
return true;
},
};
6.2 示例 B:被动钩子插件(监听群消息)
const hooks = require('../../lib/hooks');
// 模块加载即订阅
hooks.on('group_message', async ({ msg, ctx, bot }) => {
if (/谢谢/.test(msg.content || '')) {
await ctx.sendText('不客气~');
}
});
module.exports = {
meta: {
id: 'thanks-bot',
name: '自动答谢',
version: '1.0.0',
author: '开发者',
category: '消息处理',
description: '群聊中有人发"谢谢"时自动回应。',
usage: '群聊自动生效,无需命令',
},
async onMessage() { return false; }, // 不主动处理,仅用钩子
};
https://www.naigou.cn/word/kp_8r2hg/nf_uotcx/nl_gxn2i/