Greasy Fork is available in English.
为OpenWebUI的高级系统提示词加入类似nextchat的面具功能
// ==UserScript==
// @name ✨ OpenWebUI提示词助手(兼容v0.5.20)
// @namespace http://tampermonkey.net/
// @version 1.1
// @description 为OpenWebUI的高级系统提示词加入类似nextchat的面具功能
// @author tutrabbit
// @match https://127.0.0.1:8080/*
// @grant GM_setValue
// @grant GM_getValue
// @icon https://s2.loli.net/2024/12/05/lrYpNuECMKzHwOb.png
// @supportURL https://github.com/susmouse/open-webui-prompt-helper
// @license CC-BY-NC-4.0
// ==/UserScript==
(function () {
"use strict";
// 默认提示词配置
const defaultPrompts = [
{
name: "通用助手",
prompt:
"我希望你作为一个专业的助手,帮助我解决各种问题。请用简洁、清晰的语言回答我的问题。",
},
{
name: "外卖好评助手",
prompt:
"请你帮我写一则外卖好评,要求语言自然、真诚,突出商家的特色和优点,字数在50-100字之间。",
},
];
// 初始化提示词
function initPrompts() {
const savedPrompts = GM_getValue("prompts");
if (!savedPrompts) {
GM_setValue("prompts", defaultPrompts);
}
return GM_getValue("prompts");
}
// 创建按钮样式
const style = document.createElement("style");
style.textContent = `
.prompt-helper-btn {
color: #000;
margin: 3px;
padding: 3px 6px;
border: 1px solid #ccc;
border-radius: 3px;
background-color: #f8f9fa;
cursor: pointer;
display: inline-flex;
align-items: center;
font-size: 12px;
}
.prompt-helper-btn:hover {
background-color: #e9ecef;
}
.prompt-name {
color: #000;
margin-right: 3px;
cursor: pointer;
}
.delete-btn {
cursor: pointer;
color: #dc3545;
padding: 0 3px;
border-left: 1px solid #ccc;
}
.prompt-helper-container {
margin: 6px 0;
display: flex;
flex-wrap: wrap;
gap: 3px;
}
@media (max-width: 768px) {
.prompt-helper-btn {
padding: 2px 4px;
font-size: 10px;
}
.prompt-helper-container {
margin: 4px 0;
}
}
`;
document.head.appendChild(style);
// 创建按钮容器
function createButtonContainer(textarea) {
const container = document.createElement("div");
container.className = "prompt-helper-container";
return container;
}
// 创建单个按钮
function createButton(prompt, container, textarea) {
const btn = document.createElement("div");
btn.className = "prompt-helper-btn";
const nameSpan = document.createElement("span");
nameSpan.className = "prompt-name";
nameSpan.textContent = prompt.name;
nameSpan.onclick = () => {
textarea.value = prompt.prompt;
textarea.style.height = "auto";
textarea.style.height = textarea.scrollHeight + "px";
// 模拟用户输入,实现对提示词的保存
const event = new Event("input", { bubbles: true });
textarea.dispatchEvent(event);
};
const deleteSpan = document.createElement("span");
deleteSpan.className = "delete-btn";
deleteSpan.textContent = "-";
deleteSpan.onclick = () => {
const prompts = GM_getValue("prompts");
const newPrompts = prompts.filter((p) => p.name !== prompt.name);
GM_setValue("prompts", newPrompts);
refreshButtons(container, textarea);
};
btn.appendChild(nameSpan);
btn.appendChild(deleteSpan);
return btn;
}
// 创建添加按钮
function createAddButton(container, textarea) {
const btn = document.createElement("button");
btn.className = "prompt-helper-btn";
btn.textContent = "+";
btn.onclick = () => {
const name = prompt("请输入提示词名称:");
if (!name) return;
const promptText = prompt("请输入提示词内容:");
if (!promptText) return;
const prompts = GM_getValue("prompts");
prompts.push({ name, prompt: promptText });
GM_setValue("prompts", prompts);
refreshButtons(container, textarea);
};
return btn;
}
// 刷新按钮
function refreshButtons(container, textarea) {
container.innerHTML = "";
const prompts = GM_getValue("prompts");
prompts.forEach((prompt) => {
container.appendChild(createButton(prompt, container, textarea));
});
container.appendChild(createAddButton(container, textarea));
}
// 主函数
function init() {
// 使用更通用的选择器来定位文本框,忽略动态ID部分
const textarea = document.querySelector(
"div.pt-8 div.dark\\:text-gray-200.text-sm.font-primary.py-0\\.5.px-0\\.5 > div:nth-child(3) > div:nth-child(2) > div > textarea"
);
if (!textarea) {
// console.log("没有找到文本框");
setTimeout(init, 500);
return;
}
// 检查是否已经初始化
if (textarea.getAttribute("data-prompt-helper-initialized")) {
return;
}
console.log("找到文本框:", textarea);
// 标记该textarea已经初始化
textarea.setAttribute("data-prompt-helper-initialized", "true");
initPrompts();
const container = createButtonContainer(textarea);
// 将按钮容器插入到文本框之前
textarea.parentElement.insertBefore(container, textarea);
refreshButtons(container, textarea);
}
// 创建MutationObserver来监听DOM变化
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === "childList" || mutation.type === "subtree") {
init();
}
});
});
// 监听整个文档的变化
observer.observe(document.body, {
childList: true,
subtree: true,
});
// 启动脚本
init();
})();