koishi-plugin-yesimbot-extension-online-prompt
Version:
YesImBot 在线提示词加载扩展,由AI完成编写,不保证可靠性,可能出现奇怪问题
230 lines (223 loc) • 9.43 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Config = exports.usage = exports.using = exports.inject = exports.name = void 0;
exports.default = apply;
const koishi_1 = require("koishi");
exports.name = "yesimbot-extension-online-prompt";
exports.inject = ["yesimbot", "http"];
exports.using = ["yesimbot", "http"];
exports.usage = `
## 📖 使用说明
本插件为 YesImBot 提供在线提示词加载功能,支持从多个在线源动态获取自定义提示词。
### 🌟 主要特性
- 支持多个在线提示词源
- 自动缓存和刷新机制
- 优先级控制和条件启用
- 支持自定义 HTTP 请求头
- 错误重试和超时控制
### 🔧 配置说明
#### 基本配置
1. **添加提示词源**:点击"添加项目"按钮
2. **填写必要信息**:
- 名称:为提示词源起一个便于识别的名称
- URL:提示词内容的完整 URL 地址
- 优先级:数字越小优先级越高(默认:10)
- 启用状态:是否启用此提示词源
#### 高级配置
- **刷新间隔**:自动刷新提示词的时间间隔(秒),设为 0 禁用自动刷新
- **请求超时**:HTTP 请求的超时时间(秒)
- **重试次数**:请求失败时的重试次数
- **缓存设置**:启用缓存可提高性能,设置缓存过期时间
### 📝 支持的 URL 格式
- GitHub Gist Raw URL
- Notion 页面导出链接
- 任何返回纯文本的 HTTP(S) URL
### ⚠️ 注意事项
- 确保 URL 返回的是纯文本格式的提示词内容
- 建议设置合理的刷新间隔,避免频繁请求
- 如需认证,可在"请求头"中添加相应的认证信息
`;
exports.Config = koishi_1.Schema.object({
urls: koishi_1.Schema.array(koishi_1.Schema.object({
name: koishi_1.Schema.string().required().description("提示词源的名称"),
url: koishi_1.Schema.string().required().description("提示词内容的 URL(支持 GitHub Gist raw URL、Notion 导出链接等)"),
priority: koishi_1.Schema.number().default(10).description("优先级,数字越小越靠前"),
enabled: koishi_1.Schema.boolean().default(true).description("是否启用此提示词源"),
headers: koishi_1.Schema.dict(koishi_1.Schema.string()).description("可选的 HTTP 请求头"),
}))
.default([])
.description("在线提示词源配置列表"),
refreshInterval: koishi_1.Schema.number().default(300).description("刷新间隔(秒),0 表示不自动刷新"),
timeout: koishi_1.Schema.number().default(10).description("请求超时时间(秒)"),
retryAttempts: koishi_1.Schema.number().default(3).description("请求失败时的重试次数"),
enableCache: koishi_1.Schema.boolean().default(true).description("是否启用缓存"),
cacheExpiry: koishi_1.Schema.number().default(3600).description("缓存过期时间(秒)"),
});
/**
* 在线提示词加载扩展
* 支持从多个在线源(如 GitHub Gist、Notion 等)动态加载自定义提示词
*/
class OnlinePromptExtension {
constructor(ctx, config) {
this.ctx = ctx;
this.config = config;
this.cache = new Map();
this.logger = ctx.logger("online-prompt-extension");
// 在 ready 事件中执行异步初始化逻辑
this.ctx.on("ready", () => this.onMount());
this.ctx.on("dispose", () => this.onDispose());
}
/**
* 扩展挂载时的生命周期钩子
*/
async onMount() {
// 按优先级排序
this.config.urls.sort((a, b) => a.priority - b.priority);
this.logger.info("在线提示词源已按优先级排序");
this.ctx.scope.update(this.config, false);
// 注入 PromptService
const promptService = this.ctx.get('yesimbot')?.prompt;
if (!promptService) {
this.logger.error('YesImBot 服务未找到,请确保已安装并启用 koishi-plugin-yesimbot');
return;
}
// 为每个启用的提示词源注册一个片段
for (const urlConfig of this.config.urls) {
if (!urlConfig.enabled)
continue;
const snippetKey = `online.${urlConfig.name}`;
promptService.inject({
key: snippetKey,
priority: urlConfig.priority,
render: async () => {
try {
const content = await this.fetchPromptContent(urlConfig);
return content || "";
}
catch (error) {
this.logger.error(`获取在线提示词 "${urlConfig.name}" 失败:`, error);
return "";
}
}
});
this.logger.info(`已注册在线提示词片段: {{${snippetKey}}}`);
}
// 设置自动刷新
if (this.config.refreshInterval > 0) {
this.refreshTimer = setInterval(() => {
this.refreshCache();
}, this.config.refreshInterval * 1000);
this.logger.info(`已启用自动刷新,间隔 ${this.config.refreshInterval} 秒`);
}
// 预加载所有提示词内容
await this.preloadAllPrompts();
this.logger.info("在线提示词加载扩展已启动");
}
/**
* 扩展卸载时的生命周期钩子
*/
onDispose() {
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
this.refreshTimer = undefined;
}
this.cache.clear();
this.logger.info("在线提示词加载扩展已卸载");
}
/**
* 获取提示词内容
*/
async fetchPromptContent(urlConfig) {
const cacheKey = `${urlConfig.name}_${urlConfig.url}`;
// 检查缓存
if (this.config.enableCache && this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
const isExpired = Date.now() - cached.timestamp > this.config.cacheExpiry * 1000;
if (!isExpired) {
this.logger.debug(`使用缓存的提示词内容: ${urlConfig.name}`);
return cached.content;
}
}
// 从网络获取
let lastError = null;
for (let attempt = 1; attempt <= this.config.retryAttempts; attempt++) {
try {
this.logger.debug(`正在获取提示词内容: ${urlConfig.name} (尝试 ${attempt}/${this.config.retryAttempts})`);
const response = await this.ctx.http.get(urlConfig.url, {
timeout: this.config.timeout * 1000,
headers: {
'User-Agent': 'YesImBot-OnlinePrompt/1.0.0',
...urlConfig.headers,
},
});
if (typeof response !== 'string') {
throw new Error('响应不是文本格式');
}
const content = response.trim();
// 更新缓存
if (this.config.enableCache) {
this.cache.set(cacheKey, {
content,
timestamp: Date.now(),
});
}
this.logger.info(`成功获取提示词内容: ${urlConfig.name} (${content.length} 字符)`);
return content;
}
catch (error) {
lastError = error;
this.logger.warn(`获取提示词内容失败 (尝试 ${attempt}/${this.config.retryAttempts}): ${urlConfig.name} - ${error.message}`);
if (attempt < this.config.retryAttempts) {
// 等待一段时间后重试
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}
// 所有重试都失败了,返回缓存内容(如果有的话)
if (this.config.enableCache && this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
this.logger.warn(`使用过期缓存的提示词内容: ${urlConfig.name}`);
return cached.content;
}
throw lastError || new Error('未知错误');
}
/**
* 预加载所有提示词内容
*/
async preloadAllPrompts() {
const promises = this.config.urls
.filter(url => url.enabled)
.map(async (urlConfig) => {
try {
await this.fetchPromptContent(urlConfig);
}
catch (error) {
this.logger.error(`预加载提示词失败: ${urlConfig.name} - ${error.message}`);
}
});
await Promise.all(promises);
this.logger.info("提示词预加载完成");
}
/**
* 刷新缓存
*/
async refreshCache() {
this.logger.debug("开始刷新提示词缓存");
// 清除过期缓存
const now = Date.now();
for (const [key, cached] of this.cache.entries()) {
if (now - cached.timestamp > this.config.cacheExpiry * 1000) {
this.cache.delete(key);
}
}
// 重新加载所有提示词
await this.preloadAllPrompts();
}
}
/**
* 插件主函数
*/
function apply(ctx, config) {
new OnlinePromptExtension(ctx, config);
}
//# sourceMappingURL=index.js.map