🎨 优化扩展模块
This commit is contained in:
95
docs/扩展功能模块开发文档.md
Normal file
95
docs/扩展功能模块开发文档.md
Normal file
@@ -0,0 +1,95 @@
|
||||
1. 系统架构概述本系统采用前后端分离架构,旨在支持高度自定义的角色扮演体验。
|
||||
前端 (Vue 3):负责 UI 渲染、插件面板挂载、脚本沙箱执行及动态 HTML 处理。
|
||||
后端 (Go):处理业务逻辑、Prompt 组装、插件权限校验及静态资源分发。
|
||||
数据库 (PostgreSQL):存储用户数据、角色卡设定、对话历史及插件配置(JSONB)。
|
||||
|
||||
2. 插件分类定义系统支持以下两类插件,并区分 公共 (Public) 与 私人 (Private) 权限:
|
||||
插件类型实现技术核心功能设定集 (Lorebook)后端注入 + 数据库检索关键词触发知识点注入 Prompt。
|
||||
功能扩展 (Extension)前端沙箱 (Iframe/JS)增加 UI 面板、导入脚本库、渲染自定义 HTML。
|
||||
|
||||
3. 数据库模型设计3.1 插件主表 (plugins)
|
||||
```SQL
|
||||
CREATE TABLE plugins (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(100) NOT NULL,
|
||||
type VARCHAR(20) NOT NULL, -- 'lorebook' 或 'extension'
|
||||
is_public BOOLEAN DEFAULT false,
|
||||
owner_id UUID REFERENCES users(id),
|
||||
manifest JSONB, -- 存储版本、作者、入口点等元数据
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
3.2 设定条目表 (lore_items)
|
||||
```SQL
|
||||
CREATE TABLE lore_items (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
plugin_id UUID REFERENCES plugins(id) ON DELETE CASCADE,
|
||||
keywords TEXT[], -- 触发词:["魔法", "火球"]
|
||||
content TEXT NOT NULL, -- 注入内容
|
||||
priority INT DEFAULT 10 -- 插入顺序
|
||||
);
|
||||
```
|
||||
3.3 用户配置表 (user_plugin_configs)
|
||||
```SQL
|
||||
CREATE TABLE user_plugin_configs (
|
||||
user_id UUID REFERENCES users(id),
|
||||
plugin_id UUID REFERENCES plugins(id),
|
||||
is_enabled BOOLEAN DEFAULT true,
|
||||
settings JSONB, -- 存储插件的个性化设置
|
||||
PRIMARY KEY (user_id, plugin_id)
|
||||
);
|
||||
```
|
||||
|
||||
4. 后端开发:设定集注入逻辑 (Go)
|
||||
4.1 Prompt 组装流程后端在向 LLM 发送请求前,需执行以下伪逻辑:
|
||||
分词匹配:提取用户最新输入及其上下文,比对数据库中的 keywords。
|
||||
内容提取:获取命中条目的 content。
|
||||
模板拼接:
|
||||
```Plaintext
|
||||
{{System_Prompt}}
|
||||
[相关设定注入区]
|
||||
{{Injected_Lore_Content}}
|
||||
----------------
|
||||
{{Chat_History}}
|
||||
{{User_Input}}
|
||||
```
|
||||
|
||||
5. 前端开发:扩展功能实现 (Vue 3)
|
||||
5.1 插件面板挂载参考 src/Panel.vue 的设计,利用动态组件加载插件配置:功能:读取插件的 manifest.settings_schema。交互:通过 Vue 响应式表单实时预览设置效果,并保存至后端 JSONB 字段。
|
||||
5.2 脚本沙箱与 HTML 渲染参考你提供的 Iframe.vue 逻辑,为“酒馆助手”类插件提供运行环境:A. 沙箱初始化使用不可见的 <iframe> 运行插件 JS,防止污染主页面全局变量。通过 postMessage 实现主窗口与插件的通信。B. 动态 HTML 接管在聊天渲染组件中预留“渲染钩子”:JavaScript
|
||||
```
|
||||
// 在消息渲染循环中
|
||||
const renderMessage = (msg) => {
|
||||
if (helperPlugin.enabled && helperPlugin.hasRenderer) {
|
||||
// 调用插件提供的 HTML 渲染逻辑
|
||||
return helperPlugin.process(msg.content);
|
||||
}
|
||||
return standardMarkdownRender(msg.content);
|
||||
};
|
||||
```
|
||||
6. 目录结构规范后端存储 (Go 服务端)
|
||||
```Plaintext
|
||||
/storage/plugins
|
||||
/public/ # 公共插件(如官方酒馆助手)
|
||||
/tavern-helper/
|
||||
manifest.json
|
||||
index.js
|
||||
/private/ # 用户上传
|
||||
/{user_id}/
|
||||
/my-custom-ui/
|
||||
```
|
||||
前端状态 (Pinia/Vuex)
|
||||
```TypeScript
|
||||
interface PluginState {
|
||||
enabledPlugins: Plugin[];
|
||||
activeLore: LoreItem[];
|
||||
// 存储插件注入的自定义 HTML 元素
|
||||
injectedUIElements: Map<string, HTMLElement>;
|
||||
}
|
||||
```
|
||||
|
||||
7. 开发路线图 (Roadmap)
|
||||
阶段一 (核心):完成 Go 后端的关键词匹配算法,实现简单的设定集注入。
|
||||
阶段二 (管理):开发 Vue 前端的插件管理列表,支持从 JSON 导入设定集。
|
||||
阶段三 (高级):实现基于 Iframe 的脚本加载器,支持插件向侧边栏注入自定义 HTML 面板。
|
||||
阶段四 (优化):引入 PostgreSQL 的向量搜索 (pgvector),取代简单的关键词匹配,实现语义级设定调取
|
||||
72
docs/扩展加载面板.md
Normal file
72
docs/扩展加载面板.md
Normal file
@@ -0,0 +1,72 @@
|
||||
你的实现逻辑应为:扫描:Vue 前端获取插件列表,读取每个插件的 manifest.json。识别:寻找 settings_file 或类似的字段(或者约定插件根目录下的 settings.html 为面板入口)。渲染:点击插件设置时,由 Vue 动态创建一个 <iframe> 或受控的 DIV 来加载该 HTML。2. 前端实现:插件设置包装组件 (PluginSettingsWrapper.vue)由于 LittleWhiteBox 等插件是基于原生 HTML/JS 编写的,直接注入 Vue 可能会有 CSS 污染。推荐使用 Iframe 沙箱 模式。代码段<template>
|
||||
<div class="plugin-settings-container">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-lg font-bold">{{ plugin.name }}</h3>
|
||||
<el-switch v-model="isEnabled" @change="togglePlugin" />
|
||||
</div>
|
||||
|
||||
<div v-if="hasSettingsUI" class="settings-iframe-wrapper">
|
||||
<iframe
|
||||
ref="settingsIframe"
|
||||
:src="settingsUrl"
|
||||
class="w-full h-[500px] border-none"
|
||||
@load="injectBridge"
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
<div v-else class="text-gray-500">
|
||||
该插件没有独立设置面板。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
|
||||
const props = defineProps(['plugin']); // 后端返回的插件对象
|
||||
const settingsIframe = ref(null);
|
||||
|
||||
// 计算 HTML 入口地址:指向你的 Go 后端静态资源接口
|
||||
const settingsUrl = computed(() => {
|
||||
return `${import.meta.env.VITE_API_BASE}/plugins/files/${props.plugin.id}/settings.html`;
|
||||
});
|
||||
|
||||
const hasSettingsUI = computed(() => props.plugin.has_settings);
|
||||
|
||||
// 核心:注入桥接脚本(Bridge)
|
||||
const injectBridge = () => {
|
||||
const frame = settingsIframe.value;
|
||||
if (!frame) return;
|
||||
|
||||
// 向 Iframe 注入一个全局变量,让插件能调用你的系统功能
|
||||
// 例如:LittleWhiteBox 里的 JS 可能会寻找 'SillyTavern' 对象
|
||||
const bridgeScript = `
|
||||
window.parent.SillyTavern = {
|
||||
saveSettings: (data) => {
|
||||
window.parent.postMessage({ type: 'SAVE_PLUGIN_SETTINGS', data: data }, '*');
|
||||
},
|
||||
getSettings: () => ${JSON.stringify(props.plugin.user_settings)}
|
||||
};
|
||||
`;
|
||||
|
||||
try {
|
||||
const scriptTag = frame.contentDocument.createElement('script');
|
||||
scriptTag.textContent = bridgeScript;
|
||||
frame.contentDocument.head.appendChild(scriptTag);
|
||||
} catch (e) {
|
||||
console.error("跨域限制或插件加载失败", e);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
3. 后端支持 (Go):静态资源与配置下发你的 Go 后端需要能够提供插件目录下的文件访问。Go// Go 伪代码:静态文件分发
|
||||
r.GET("/plugins/files/:plugin_id/*filepath", func(c *gin.Context) {
|
||||
pluginID := c.Param("plugin_id")
|
||||
filePath := c.Param("filepath")
|
||||
|
||||
// 从数据库查询该插件的物理路径
|
||||
basePath := db.GetPluginPath(pluginID)
|
||||
|
||||
// 返回对应的 HTML/JS/CSS
|
||||
c.File(filepath.Join(basePath, filePath))
|
||||
})
|
||||
4. 针对 LittleWhiteBox 的适配建议通过分析 LittleWhiteBox 的代码,它包含了大量的模块(如 modules/tts, modules/novel-draw)。这些模块通常通过 index.js 加载。如果你要完美支持它,需要解决以下两个关键点:CSS 样式映射:LittleWhiteBox 的样式可能依赖原版酒馆的 CSS 类名(如 .menu_button, .panel)。解决方案:在你的 Vue 项目中,为插件 iframe 注入一个包含“酒馆兼容层样式”的 CSS 文件,模拟原版的 UI 环境。事件监听 (Event Bus):LittleWhiteBox 里的很多功能(如 modules/event-manager.js)是基于事件触发的。解决方案:在你的 PluginContext 中实现一个简单的事件中心,当你的 Vue 界面发生“消息发送”、“收到回复”等动作时,通过 postMessage 通知 Iframe 内的插件。5. 文档补全:插件设置渲染规范步骤开发者操作系统行为检测后端扫描 manifest.json发现 settings_file: "settings.html"。入口Vue 点击插件列表中的“设置”图标在右侧弹出 Drawer 或 Modal,挂载 PluginSettingsWrapper。握手Iframe 加载完成后执行注入将当前用户的 PgSQL 配置注入插件内存。持久化插件内点击保存插件调用 SillyTavern.saveSettings -> Vue 捕获消息 -> Go 写入 PgSQL。
|
||||
Reference in New Issue
Block a user