Add files via upload
This commit is contained in:
@@ -858,7 +858,7 @@ function renderContent(text) {
|
||||
if (!text) return '';
|
||||
let html = String(text).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
|
||||
html = html.replace(/\[(?:image|图片)\s*:\s*([^\]]+)\]/gi, (_, inner) => {
|
||||
html = html.replace(/\[(?:img|图片)\s*:\s*([^\]]+)\]/gi, (_, inner) => {
|
||||
const tags = parseImageToken(inner);
|
||||
if (!tags) return _;
|
||||
return `<div class="fw-img-slot" data-raw="${encodeURIComponent(inner)}"></div>`;
|
||||
@@ -900,6 +900,7 @@ function renderContent(text) {
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
function renderMessages() {
|
||||
const container = document.getElementById('messages');
|
||||
const { history, isStreaming, editingIndex } = state;
|
||||
|
||||
@@ -272,9 +272,9 @@ export async function handleGenerate(data, postToFrame) {
|
||||
|
||||
export const IMG_GUIDELINE = `## 模拟图片
|
||||
如果需要发图、照片给对方时,可以在聊天文本中穿插以下格式行,进行图片模拟:
|
||||
[image: Subject, Appearance, Background, Atmosphere, Extra descriptors]
|
||||
[img: Subject, Appearance, Background, Atmosphere, Extra descriptors]
|
||||
- tag必须为英文,用逗号分隔,使用Danbooru风格的tag,5-15个tag
|
||||
- 第一个tag须固定为人物数量标签,如: 1girl, 1boy, 2girls, solo, etc.
|
||||
- 可以多张照片: 每行一张 [image: ...]
|
||||
- 可以多张照片: 每行一张 [img: ...]
|
||||
- 当需要发送的内容尺度较大时加上nsfw相关tag
|
||||
- image部分也需要在<msg>内`;
|
||||
|
||||
@@ -25,6 +25,7 @@ const CSS_INJECTED_KEY = 'xb-me-css-injected';
|
||||
|
||||
let currentAudio = null;
|
||||
let imageObserver = null;
|
||||
let domObserver = null; // ▼ 新增
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// 初始化与清理
|
||||
@@ -39,6 +40,7 @@ export async function initMessageEnhancer() {
|
||||
injectStyles();
|
||||
await loadVoices();
|
||||
initImageObserver();
|
||||
initDomObserver(); // ▼ 新增
|
||||
|
||||
events.on(event_types.CHAT_CHANGED, () => {
|
||||
clearQueue();
|
||||
@@ -65,12 +67,99 @@ export function cleanupMessageEnhancer() {
|
||||
imageObserver = null;
|
||||
}
|
||||
|
||||
// ▼ 新增
|
||||
if (domObserver) {
|
||||
domObserver.disconnect();
|
||||
domObserver = null;
|
||||
}
|
||||
|
||||
if (currentAudio) {
|
||||
currentAudio.pause();
|
||||
currentAudio = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// DOM 变化观察器(新增)
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
function initDomObserver() {
|
||||
if (domObserver) return;
|
||||
|
||||
const chatContainer = document.getElementById('chat');
|
||||
if (!chatContainer) {
|
||||
// 如果 chat 容器还没加载,延迟重试
|
||||
setTimeout(initDomObserver, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
// 用于防抖处理
|
||||
let pendingTexts = new Set();
|
||||
let debounceTimer = null;
|
||||
|
||||
domObserver = new MutationObserver((mutations) => {
|
||||
const settings = extension_settings[EXT_ID];
|
||||
if (!settings?.fourthWall?.enabled) return;
|
||||
|
||||
for (const mutation of mutations) {
|
||||
let mesText = null;
|
||||
|
||||
if (mutation.type === 'childList') {
|
||||
for (const node of mutation.addedNodes) {
|
||||
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
||||
|
||||
if (node.classList?.contains('mes_text')) {
|
||||
mesText = node;
|
||||
} else if (node.classList?.contains('mes')) {
|
||||
mesText = node.querySelector('.mes_text');
|
||||
} else {
|
||||
mesText = node.querySelector?.('.mes_text');
|
||||
}
|
||||
|
||||
if (mesText && hasUnrenderedPlaceholders(mesText)) {
|
||||
pendingTexts.add(mesText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mutation.target?.classList?.contains('mes_text')) {
|
||||
if (hasUnrenderedPlaceholders(mutation.target)) {
|
||||
pendingTexts.add(mutation.target);
|
||||
}
|
||||
} else if (mutation.target?.closest?.('.mes_text')) {
|
||||
const target = mutation.target.closest('.mes_text');
|
||||
if (hasUnrenderedPlaceholders(target)) {
|
||||
pendingTexts.add(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingTexts.size > 0 && !debounceTimer) {
|
||||
debounceTimer = setTimeout(() => {
|
||||
pendingTexts.forEach(mesText => {
|
||||
if (document.contains(mesText)) {
|
||||
enhanceMessageContent(mesText);
|
||||
}
|
||||
});
|
||||
pendingTexts.clear();
|
||||
debounceTimer = null;
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
|
||||
domObserver.observe(chatContainer, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
|
||||
function hasUnrenderedPlaceholders(mesText) {
|
||||
if (!mesText) return false;
|
||||
const html = mesText.innerHTML;
|
||||
return /\[(?:img|图片)\s*:\s*[^\]]+\]/i.test(html) ||
|
||||
/\[(?:voice|语音)\s*:[^\]]+\]/i.test(html);
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// 事件处理
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
@@ -271,7 +360,7 @@ function enhanceMessageContent(container) {
|
||||
let enhanced = html;
|
||||
let hasChanges = false;
|
||||
|
||||
enhanced = enhanced.replace(/\[(?:image|图片)\s*:\s*([^\]]+)\]/gi, (match, inner) => {
|
||||
enhanced = enhanced.replace(/\[(?:img|图片)\s*:\s*([^\]]+)\]/gi, (match, inner) => {
|
||||
const tags = parseImageToken(inner);
|
||||
if (!tags) return match;
|
||||
hasChanges = true;
|
||||
|
||||
Reference in New Issue
Block a user