';
html += `
`;
userStickers.forEach((sticker, index) => {
@@ -210,6 +232,9 @@ export function refreshEmojiGrid() {
// 绑定添加按钮事件
document.getElementById('wechat-emoji-add-btn')?.addEventListener('click', showAddStickerDialog);
+ // 绑定清空全部按钮事件
+ document.getElementById('wechat-emoji-clear-all')?.addEventListener('click', clearAllStickers);
+
// 绑定用户表情左滑删除
content.querySelectorAll('.wechat-emoji-swipe-container').forEach(container => {
setupSwipeToDelete(container);
@@ -243,6 +268,7 @@ function setupSwipeToDelete(container) {
}
isDragging = true;
startX = e.type.includes('mouse') ? e.clientX : e.touches[0].clientX;
+ currentX = startX; // 初始化 currentX,确保点击时 diff 为 0
item.style.transition = 'none';
}
@@ -502,6 +528,24 @@ function deleteSticker(index) {
}
}
+// 清空所有用户表情
+function clearAllStickers() {
+ const settings = getSettings();
+ const stickers = settings.stickers || [];
+
+ if (stickers.length === 0) {
+ showToast('没有表情可清空', 'info');
+ return;
+ }
+
+ if (!confirm(`确定要清空全部 ${stickers.length} 个自定义表情吗?此操作不可恢复!`)) return;
+
+ settings.stickers = [];
+ requestSave();
+ refreshEmojiGrid();
+ showToast('已清空所有表情');
+}
+
// 初始化表情面板
export function initEmojiPanel() {
if (emojiPanelInited) return;
@@ -511,6 +555,9 @@ export function initEmojiPanel() {
emojiPanelInited = true;
+ // 执行迁移:去除现有表情名称的数字后缀
+ migrateStickersRemoveNumericSuffix();
+
// 绑定标签切换事件
document.querySelectorAll('.wechat-emoji-tab').forEach(tab => {
tab.addEventListener('click', () => {
diff --git a/gift.js b/gift.js
index c26671b..0a2f39c 100644
--- a/gift.js
+++ b/gift.js
@@ -18,6 +18,8 @@ const ICON_GIFT_CHARACTER = `
`;
+const ICON_GIFT_BOTH = `
`;
+
// 礼物分类数据
const GIFT_CATEGORIES = {
normal: {
@@ -48,7 +50,9 @@ const GIFT_CATEGORIES = {
{ id: 'butterfly', name: '穿戴式小蝴蝶', emoji: '🦋', desc: '隐蔽穿戴震动', hasControl: true, hasShock: false },
{ id: 'collar', name: '项圈', emoji: '⭕', desc: '精致的项圈', hasControl: false },
{ id: 'candle', name: '低温蜡烛', emoji: '🕯️', desc: '安全的低温蜡烛', hasControl: false },
- { id: 'lingerie', name: '情趣内衣', emoji: '👙', desc: '性感的情趣内衣', hasControl: false }
+ { id: 'lingerie', name: '情趣内衣', emoji: '👙', desc: '性感的情趣内衣', hasControl: false },
+ { id: 'fuckingMachine', name: '炮机', emoji: '🔧', desc: '电动炮机', hasControl: true, hasShock: false },
+ { id: 'masturbatorCup', name: '飞机杯', emoji: '🥤', desc: '电动飞机杯', hasControl: true, hasShock: false }
]
}
};
@@ -138,6 +142,10 @@ function renderGiftContent() {
${ICON_GIFT_USER}
送用户
+
`;
@@ -304,7 +312,7 @@ export async function sendGift() {
const giftsToSend = [...selectedGifts];
const giftNames = giftsToSend.map(g => g.name).join('、');
const giftEmojis = giftsToSend.map(g => g.emoji).join(' ');
- const targetText = target === 'character' ? '送TA' : '送自己';
+ const targetText = target === 'character' ? '送TA' : target === 'user' ? '送自己' : '同时送';
const giftMessage = `[情趣礼物套装] ${giftEmojis} ${giftNames}(${targetText})${customDesc ? ` - ${customDesc}` : ''}`;
const giftRecord = {
@@ -378,12 +386,20 @@ export async function sendGift() {
showTypingIndicator(contact);
// 构建给AI的提示
- const targetTextAI = target === 'character' ? '你' : '用户';
+ let targetTextAI;
+ if (target === 'character') {
+ targetTextAI = '角色(你)';
+ } else if (target === 'user') {
+ targetTextAI = '用户';
+ } else {
+ targetTextAI = '你和用户两人同时';
+ }
const aiPrompt = `[系统提示:用户刚刚购买了一套情趣玩具套装,包括:${giftNames},准备送给${targetTextAI}使用。商品正在配送中,预计很快就会送达。${customDesc ? `用户附言:${customDesc}` : ''}
请根据你的角色性格,对这套即将到来的礼物做出反应:
- 如果是送给你的:可以表现出期待、害羞、紧张、好奇等情绪,可以问用户打算怎么用这些
- 如果是送给用户的:可以表现出好奇、调侃、期待看到用户反应等
+- 如果是同时送给两人的:可以表现出兴奋、期待、好奇等,想象两人一起使用的场景
- 根据你的人设和与用户的关系,反应可以是含蓄的、热情的、或者假装矜持的
- 回复不要太短,请展现角色的内心活动和情绪变化
@@ -438,7 +454,7 @@ export async function sendGift() {
// 构建礼物消息
let giftMessage;
if (isToy) {
- const targetText = target === 'character' ? '送TA' : '送自己';
+ const targetText = target === 'character' ? '送TA' : target === 'user' ? '送自己' : '同时送';
giftMessage = `[情趣礼物] ${gift.emoji} ${gift.name}(${targetText})${customDesc ? ` - ${customDesc}` : ''}`;
} else {
giftMessage = `[礼物] ${gift.emoji} ${gift.name}${customDesc ? ` - ${customDesc}` : ''}`;
@@ -514,12 +530,20 @@ export async function sendGift() {
let aiPrompt;
if (isToy && gift.hasControl) {
// 可控制的情趣玩具 - 配送中提示词
- const targetText = target === 'character' ? '你' : '用户';
+ let targetText;
+ if (target === 'character') {
+ targetText = '你';
+ } else if (target === 'user') {
+ targetText = '用户';
+ } else {
+ targetText = '你和用户两人同时';
+ }
aiPrompt = `[系统提示:用户刚刚购买了一个${gift.name}(${gift.desc}),准备送给${targetText}使用。商品正在配送中,预计很快就会送达。${customDesc ? `用户附言:${customDesc}` : ''}
请根据你的角色性格,对这个即将到来的礼物做出反应:
- 如果是送给你的:可以表现出期待、害羞、紧张、好奇等情绪
- 如果是送给用户的:可以表现出好奇、调侃、期待看到用户反应等
+- 如果是同时送给两人的:可以表现出兴奋、期待、好奇等,想象两人一起使用的场景
- 根据你的人设和与用户的关系,反应可以是含蓄的、热情的、或者假装矜持的
- 可以询问用户打算怎么用、什么时候用等
- 回复不要太短,请展现角色的内心活动和情绪变化
@@ -750,7 +774,7 @@ export function appendGiftMessage(role, gift, isToy, customDesc, contact, target
const giftTypeClass = isToy ? 'wechat-gift-bubble-toy' : '';
let giftTypeLabel = isToy ? '情趣礼物' : '礼物';
if (isToy && target) {
- giftTypeLabel = target === 'character' ? '情趣礼物·送TA' : '情趣礼物·送自己';
+ giftTypeLabel = target === 'character' ? '情趣礼物·送TA' : target === 'user' ? '情趣礼物·送自己' : '情趣礼物·同时送';
}
messageDiv.innerHTML = `
@@ -796,7 +820,7 @@ export function appendMultiGiftMessage(role, gifts, customDesc, contact, target
: firstChar;
}
- const giftTypeLabel = target === 'character' ? '送TA' : '送自己';
+ const giftTypeLabel = target === 'character' ? '送TA' : target === 'user' ? '送自己' : '同时送';
// 生成每个礼物的标签
const giftTagsHtml = gifts.map(g => `
diff --git a/group-chat.js b/group-chat.js
index cf4e50b..dfe553f 100644
--- a/group-chat.js
+++ b/group-chat.js
@@ -4,7 +4,7 @@
import { requestSave, saveNow } from './save-manager.js';
import { getContext } from '../../../extensions.js';
-import { getSettings, SUMMARY_MARKER_PREFIX, getUserStickers, parseMemeTag, MEME_PROMPT_TEMPLATE, splitAIMessages } from './config.js';
+import { getSettings, SUMMARY_MARKER_PREFIX, getUserStickers, parseMemeTag, getMemePromptTemplate, splitAIMessages } from './config.js';
import { showToast } from './toast.js';
import { escapeHtml, sleep, formatMessageTime, calculateVoiceDuration, bindImageLoadFallback } from './utils.js';
import { getUserAvatarHTML, refreshChatList, getUserPersonaFromST } from './ui.js';
@@ -1279,7 +1279,7 @@ ${userStickers.map((s, i) => ` ${i + 1}. ${s.name || '表情' + (i + 1)}`).join
// Meme 表情包提示词(如果启用)
if (settings.memeStickersEnabled) {
- systemPrompt += '\n\n' + MEME_PROMPT_TEMPLATE;
+ systemPrompt += '\n\n' + getMemePromptTemplate();
}
return systemPrompt;
diff --git a/listen-together.js b/listen-together.js
index b697955..24392a7 100644
--- a/listen-together.js
+++ b/listen-together.js
@@ -600,7 +600,7 @@ function filterListenMessage(text) {
// 过滤 meme 表情包
reply = reply.replace(/<\s*meme\s*>[\s\S]*?<\s*\/\s*meme\s*>/gi, '').trim();
// 过滤 [表情:xxx]
- reply = reply.replace(/\[表情[::][^\]]*\]/g, '').trim();
+ reply = reply.replace(/\[表情\s*[::∶][^\]]*\]/g, '').trim();
// 过滤 [照片:xxx]
reply = reply.replace(/\[照片[::][^\]]*\]/g, '').trim();
// 过滤 [语音:xxx]
diff --git a/main.js b/main.js
index a9ffa8b..e309898 100644
--- a/main.js
+++ b/main.js
@@ -6,7 +6,7 @@ console.log('[可乐] main.js 开始加载...');
import { requestSave, setupUnloadSave } from './save-manager.js';
-import { loadSettings, getSettings, MEME_PROMPT_TEMPLATE } from './config.js';
+import { loadSettings, getSettings } from './config.js';
import { generatePhoneHTML } from './phone-html.js';
import { showPage, refreshChatList, updateMePageInfo, getUserPersonaFromST, updateTabBadge } from './ui.js';
import { showToast } from './toast.js';
diff --git a/message-menu.js b/message-menu.js
index 4ba069e..25a25c0 100644
--- a/message-menu.js
+++ b/message-menu.js
@@ -26,7 +26,7 @@ const menuItems = [
{ id: 'transcribe', icon: 'transcribe', text: '转文字', voiceOnly: true },
{ id: 'quote', icon: 'quote', text: '引用' },
{ id: 'recall', icon: 'recall', text: '撤回', userOnly: true },
- { id: 'delete', icon: 'delete', text: '删除' },
+ { id: 'regenerate', icon: 'regenerate', text: '重新生成', userOnly: true },
{ id: 'multiselect', icon: 'multiselect', text: '多选' }
];
@@ -50,11 +50,10 @@ const icons = {