diff --git a/style.css b/style.css
index 2f4ca3f..2cfbe64 100644
--- a/style.css
+++ b/style.css
@@ -4295,6 +4295,49 @@
transform: scale(0.95);
}
+/* 左滑删除容器 */
+.wechat-emoji-swipe-container {
+ position: relative;
+ width: 100%;
+ aspect-ratio: 1;
+ overflow: hidden;
+ border-radius: 8px;
+}
+
+.wechat-emoji-swipe-container .wechat-emoji-user-item {
+ position: relative;
+ z-index: 2;
+ width: 100%;
+ height: 100%;
+ will-change: transform;
+}
+
+.wechat-emoji-swipe-container .wechat-emoji-user-item:active {
+ transform: none;
+}
+
+/* 删除背景 */
+.wechat-emoji-delete-bg {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 50px;
+ height: 100%;
+ background: #ff3b30;
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 12px;
+ z-index: 1;
+ cursor: pointer;
+ border-radius: 0 8px 8px 0;
+}
+
+.wechat-emoji-delete-bg:active {
+ background: #d32f2f;
+}
+
.wechat-emoji-item img {
width: 100%;
height: 100%;
@@ -10561,6 +10604,64 @@
color: #ff6b6b;
}
+/* 多选按钮 */
+.wechat-gift-multi-select-btn {
+ position: absolute;
+ right: 15px;
+ top: 50%;
+ transform: translateY(-50%);
+ padding: 6px 14px;
+ background: linear-gradient(135deg, #ff6b8a, #ff4d6d);
+ border: none;
+ border-radius: 16px;
+ color: #fff;
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s;
+ box-shadow: 0 2px 8px rgba(255, 77, 109, 0.3);
+}
+
+.wechat-gift-multi-select-btn:hover {
+ background: linear-gradient(135deg, #ff7a96, #ff5c7a);
+ box-shadow: 0 3px 12px rgba(255, 77, 109, 0.4);
+}
+
+.wechat-gift-multi-select-btn.active {
+ background: linear-gradient(135deg, #ff8fab, #ff6b8a);
+}
+
+/* 多选勾选标记 */
+.wechat-gift-check-mark {
+ position: absolute;
+ top: 6px;
+ right: 6px;
+ width: 20px;
+ height: 20px;
+ background: linear-gradient(135deg, #ff6b8a, #ff4d6d);
+ border-radius: 50%;
+ color: #fff;
+ font-size: 12px;
+ font-weight: bold;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 2px 6px rgba(255, 77, 109, 0.4);
+ animation: checkMarkPop 0.2s ease-out;
+}
+
+@keyframes checkMarkPop {
+ 0% {
+ transform: scale(0);
+ }
+ 70% {
+ transform: scale(1.2);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
/* 礼物描述输入 */
.wechat-gift-desc-row {
margin-top: 15px;
@@ -11127,6 +11228,52 @@
position: relative;
}
+/* ========== 加急配送弹窗样式 ========== */
+.wechat-express-modal-content {
+ background: #ffffff;
+ border-radius: 12px;
+ padding: 24px 20px;
+ width: 280px;
+ text-align: center;
+}
+
+.wechat-express-text {
+ color: #000000;
+ font-size: 16px;
+ line-height: 1.5;
+ margin-bottom: 24px;
+}
+
+.wechat-express-actions {
+ display: flex;
+ gap: 12px;
+}
+
+.wechat-express-btn {
+ flex: 1;
+ padding: 10px 0;
+ border: none;
+ border-radius: 8px;
+ font-size: 15px;
+ cursor: pointer;
+ transition: opacity 0.2s;
+}
+
+.wechat-express-btn.confirm {
+ background: #FFC107;
+ color: #000000;
+ font-weight: 500;
+}
+
+.wechat-express-btn.cancel {
+ background: #E5E5E5;
+ color: #333333;
+}
+
+.wechat-express-btn:active {
+ opacity: 0.8;
+}
+
/* ========== 礼物送达询问弹窗样式 ========== */
.wechat-gift-arrival-content {
background: #fff !important;
@@ -11298,6 +11445,33 @@
background: linear-gradient(135deg, #ffc107, #ff9800);
}
+/* 媒体按钮(麦克风/摄像头) */
+.wechat-toy-btn-media {
+ width: 60px;
+ height: 60px;
+ background: linear-gradient(135deg, #ff6b8a, #ff4d6d);
+ border-color: rgba(255, 107, 138, 0.3);
+ box-shadow: 0 4px 12px rgba(255, 77, 109, 0.3);
+}
+
+.wechat-toy-btn-media svg {
+ color: #fff;
+}
+
+.wechat-toy-btn-media:hover {
+ background: linear-gradient(135deg, #ff7a96, #ff5c7a);
+}
+
+.wechat-toy-btn-media.active {
+ background: linear-gradient(135deg, #ff8fab, #ff6b8a);
+ border-color: #ff8fab;
+ box-shadow: 0 0 20px rgba(255, 143, 171, 0.5);
+}
+
+.wechat-toy-btn-media.active svg {
+ color: #fff;
+}
+
.wechat-toy-shock-row {
padding-top: 5px;
border-top: 1px dashed rgba(255, 107, 138, 0.3);
@@ -11365,6 +11539,186 @@
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
+/* 系统消息(如切换玩具提示) */
+.wechat-toy-control-msg.system {
+ align-self: center;
+ background: rgba(255, 107, 138, 0.15);
+ color: #ff6b8a;
+ font-size: 12px;
+ padding: 6px 14px;
+ border-radius: 16px;
+ max-width: none;
+}
+
+/* 多玩具轮盘选择器 */
+.wechat-toy-wheel-container {
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 180px;
+ margin: 10px 0;
+}
+
+.wechat-toy-wheel-heart {
+ width: 50px;
+ height: 50px;
+ background: linear-gradient(135deg, #ff6b8a, #ff4d6d);
+ border: none;
+ border-radius: 50%;
+ color: #fff;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 4px 15px rgba(255, 77, 109, 0.4);
+ transition: all 0.3s ease;
+ z-index: 10;
+ animation: heartPulse 2s ease-in-out infinite;
+}
+
+@keyframes heartPulse {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.05);
+ }
+}
+
+.wechat-toy-wheel-heart:hover {
+ transform: scale(1.1);
+ box-shadow: 0 6px 20px rgba(255, 77, 109, 0.5);
+}
+
+.wechat-toy-wheel-heart:active {
+ transform: scale(0.95);
+}
+
+.wechat-toy-wheel-heart svg {
+ width: 24px;
+ height: 24px;
+}
+
+.wechat-toy-wheel-options {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ pointer-events: none;
+}
+
+.wechat-toy-wheel-options.open {
+ pointer-events: auto;
+}
+
+.wechat-toy-wheel-option {
+ position: absolute;
+ width: 56px;
+ height: 56px;
+ background: rgba(255, 255, 255, 0.95);
+ border: 2px solid rgba(255, 107, 138, 0.3);
+ border-radius: 50%;
+ cursor: pointer;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 2px;
+ opacity: 0;
+ transform: translate(-50%, -50%) scale(0);
+ transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+ box-shadow: 0 3px 12px rgba(0, 0, 0, 0.15);
+ left: 50%;
+ top: 50%;
+}
+
+.wechat-toy-wheel-options.open .wechat-toy-wheel-option {
+ opacity: 1;
+ transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) scale(1);
+}
+
+.wechat-toy-wheel-option:hover {
+ background: #fff;
+ border-color: #ff6b8a;
+ transform: translate(calc(-50% + var(--x)), calc(-50% + var(--y))) scale(1.15);
+ box-shadow: 0 5px 20px rgba(255, 107, 138, 0.3);
+}
+
+.wechat-toy-wheel-option.active {
+ background: linear-gradient(135deg, #fff0f3, #ffe0e6);
+ border-color: #ff6b8a;
+ box-shadow: 0 0 0 3px rgba(255, 107, 138, 0.2);
+}
+
+.wechat-toy-wheel-option .emoji {
+ font-size: 20px;
+ line-height: 1;
+}
+
+.wechat-toy-wheel-option .name {
+ font-size: 9px;
+ color: #666;
+ max-width: 50px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.wechat-toy-wheel-option.active .name {
+ color: #ff6b8a;
+ font-weight: 500;
+}
+
+/* 轮盘选择器移动端适配 */
+@media (max-width: 420px) {
+ .wechat-toy-wheel-container {
+ height: 150px;
+ }
+
+ .wechat-toy-wheel-heart {
+ width: 44px;
+ height: 44px;
+ }
+
+ .wechat-toy-wheel-heart svg {
+ width: 20px;
+ height: 20px;
+ }
+
+ .wechat-toy-wheel-option {
+ width: 48px;
+ height: 48px;
+ }
+
+ .wechat-toy-wheel-option .emoji {
+ font-size: 16px;
+ }
+
+ .wechat-toy-wheel-option .name {
+ font-size: 8px;
+ max-width: 44px;
+ }
+}
+
+/* 轮盘背景遮罩(点击关闭) */
+.wechat-toy-wheel-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: transparent;
+ z-index: 5;
+ display: none;
+ pointer-events: none;
+}
+
+.wechat-toy-wheel-overlay.active {
+ display: block;
+ pointer-events: auto;
+}
+
@keyframes fadeIn {
from {
opacity: 0;
@@ -11664,8 +12018,8 @@
/* ===== 悬浮球样式 ===== */
.wechat-floating-ball {
position: fixed;
- width: 60px;
- height: 60px;
+ width: 30px;
+ height: 30px;
z-index: 99999;
cursor: pointer;
display: flex;
@@ -11679,24 +12033,24 @@
}
.wechat-floating-ball:hover {
- transform: scale(1.08);
+ transform: scale(1.15);
}
.wechat-floating-ball:active,
.wechat-floating-ball.dragging {
- transform: scale(0.95);
+ transform: scale(0.92);
opacity: 0.9;
}
.wechat-floating-ball .floating-ball-svg {
width: 100%;
height: 100%;
- filter: drop-shadow(0 2px 8px rgba(255, 182, 193, 0.4));
+ filter: drop-shadow(0 1px 4px rgba(255, 182, 193, 0.5));
transition: filter 0.2s ease;
}
.wechat-floating-ball:hover .floating-ball-svg {
- filter: drop-shadow(0 4px 12px rgba(255, 182, 193, 0.6));
+ filter: drop-shadow(0 2px 6px rgba(255, 182, 193, 0.7));
}
/* 悬浮球呼吸动画(可选,可删除) */
@@ -11705,7 +12059,7 @@
transform: scale(1);
}
50% {
- transform: scale(1.03);
+ transform: scale(1.05);
}
}
diff --git a/summary.js b/summary.js
index 6f58321..bd4fb43 100644
--- a/summary.js
+++ b/summary.js
@@ -323,11 +323,11 @@ export function generateSummaryPrompt(allChats, cupNumber) {
- 不要使用markdown代码块
- 直接以 { 开头,以 } 结尾
- keys: 3-5个能代表本次聊天核心内容的关键词(人名、地点、事件等)
-- content: 原样复制的对话记录,每条一行,格式为"发言者: 内容"
+- content: 以"以下是线上聊天内容:"开头,然后原样复制对话记录,每条一行,格式为"发言者: 内容"
- comment: "${getCupName(cupNumber)}"
【JSON示例】
-{"keys":["公园","约会","周末"],"content":"{{user}}: 今天去哪玩?\\n{{char}}: 去公园吧\\n{{user}}: 好呀\\n{{char}}: 那我们下午2点见","comment":"${getCupName(cupNumber)}"}
+{"keys":["公园","约会","周末"],"content":"以下是线上聊天内容:\\n{{user}}: 今天去哪玩?\\n{{char}}: 去公园吧\\n{{user}}: 好呀\\n{{char}}: 那我们下午2点见","comment":"${getCupName(cupNumber)}"}
`;
}
diff --git a/toy-control.js b/toy-control.js
index 0585911..fc1650d 100644
--- a/toy-control.js
+++ b/toy-control.js
@@ -18,7 +18,13 @@ const TOY_ICONS = {
wave: `
`,
pause: `
`,
shock: `
`,
- back: `
`
+ back: `
`,
+ micOn: `
`,
+ micOff: `
`,
+ cameraOn: `
`,
+ cameraOff: `
`,
+ // 像素爱心图标(用于多玩具切换)
+ pixelHeart: `
`
};
// 控制模式定义
@@ -73,11 +79,21 @@ let toyControlState = {
currentMode: null,
messages: [],
activeModes: new Set(),
- sessionStartTime: null
+ sessionStartTime: null,
+ micEnabled: false, // 麦克风状态
+ cameraEnabled: false, // 摄像头状态
+ // 多玩具支持
+ isMulti: false, // 是否多玩具模式
+ toys: [], // 多玩具列表
+ currentToyIndex: 0, // 当前控制的玩具索引
+ wheelOpen: false // 轮盘是否展开
};
// 显示控制界面
export function showToyControlPage(gift, contact, contactIndex) {
+ // 判断是否多玩具模式
+ const isMulti = gift.isMulti === true;
+
toyControlState = {
isActive: true,
gift: gift,
@@ -87,9 +103,30 @@ export function showToyControlPage(gift, contact, contactIndex) {
currentMode: null,
messages: [],
activeModes: new Set(),
- sessionStartTime: Date.now()
+ sessionStartTime: Date.now(),
+ micEnabled: false,
+ cameraEnabled: false,
+ // 多玩具支持
+ isMulti: isMulti,
+ toys: isMulti ? gift.toys : [],
+ currentToyIndex: 0,
+ wheelOpen: false
};
+ // 如果是多玩具模式,设置当前玩具为第一个
+ if (isMulti && gift.toys && gift.toys.length > 0) {
+ const firstToy = gift.toys[0];
+ toyControlState.gift = {
+ ...gift,
+ giftId: firstToy.giftId,
+ giftName: firstToy.giftName,
+ giftEmoji: firstToy.giftEmoji,
+ giftDesc: firstToy.giftDesc,
+ hasControl: firstToy.hasControl,
+ hasShock: firstToy.hasShock
+ };
+ }
+
// 标记正在使用
if (contact.pendingGifts) {
const pendingGift = contact.pendingGifts.find(g => g.timestamp === gift.timestamp);
@@ -159,6 +196,9 @@ function renderToyControlPage() {
`;
buttonsEl.innerHTML = buttonsHtml;
@@ -187,12 +230,246 @@ function renderToyControlPage() {
}
}
- // 清空消息
- if (messagesEl) {
+ // 多玩具轮盘选择器
+ renderToyWheelSelector();
+
+ // 不清空消息(保留聊天内容)
+ // 只在首次进入时清空
+ if (messagesEl && messagesEl.children.length === 0 && toyControlState.messages.length === 0) {
messagesEl.innerHTML = '';
}
}
+// 渲染多玩具轮盘选择器
+function renderToyWheelSelector() {
+ // 移除旧的轮盘和遮罩
+ const existingWheel = document.getElementById('wechat-toy-wheel-container');
+ if (existingWheel) {
+ existingWheel.remove();
+ }
+ const existingOverlay = document.getElementById('wechat-toy-wheel-overlay');
+ if (existingOverlay) {
+ existingOverlay.remove();
+ }
+
+ // 只在多玩具模式下显示
+ if (!toyControlState.isMulti || toyControlState.toys.length <= 1) return;
+
+ const controlPage = document.getElementById('wechat-toy-control-page');
+ if (!controlPage) return;
+
+ // 创建背景遮罩(点击关闭轮盘)
+ const overlay = document.createElement('div');
+ overlay.id = 'wechat-toy-wheel-overlay';
+ overlay.className = `wechat-toy-wheel-overlay ${toyControlState.wheelOpen ? 'active' : ''}`;
+
+ // 创建轮盘容器
+ const wheelContainer = document.createElement('div');
+ wheelContainer.id = 'wechat-toy-wheel-container';
+ wheelContainer.className = 'wechat-toy-wheel-container';
+
+ // 创建中心爱心按钮
+ const heartBtn = document.createElement('button');
+ heartBtn.className = 'wechat-toy-wheel-heart';
+ heartBtn.innerHTML = TOY_ICONS.pixelHeart;
+ heartBtn.title = '切换玩具';
+
+ // 创建轮盘选项
+ const wheelOptions = document.createElement('div');
+ wheelOptions.className = `wechat-toy-wheel-options ${toyControlState.wheelOpen ? 'open' : ''}`;
+
+ const toys = toyControlState.toys;
+ const angleStep = 360 / toys.length;
+ // 移动端使用更小的半径
+ const isMobile = window.innerWidth <= 420;
+ const radius = isMobile ? 55 : 70;
+
+ toys.forEach((toy, index) => {
+ const option = document.createElement('button');
+ option.className = `wechat-toy-wheel-option ${index === toyControlState.currentToyIndex ? 'active' : ''}`;
+ option.dataset.toyIndex = index;
+
+ // 计算位置(从顶部开始,顺时针排列)
+ const angle = -90 + (angleStep * index); // -90 从顶部开始
+ const x = Math.cos(angle * Math.PI / 180) * radius;
+ const y = Math.sin(angle * Math.PI / 180) * radius;
+
+ option.style.setProperty('--x', `${x}px`);
+ option.style.setProperty('--y', `${y}px`);
+ option.innerHTML = `
`;
+
+ wheelOptions.appendChild(option);
+ });
+
+ wheelContainer.appendChild(wheelOptions);
+ wheelContainer.appendChild(heartBtn);
+
+ // 插入遮罩和轮盘到控制区域上方
+ const chatArea = controlPage.querySelector('.wechat-toy-control-chat');
+ if (chatArea) {
+ chatArea.parentNode.insertBefore(overlay, chatArea);
+ chatArea.parentNode.insertBefore(wheelContainer, chatArea);
+ } else {
+ controlPage.appendChild(overlay);
+ controlPage.appendChild(wheelContainer);
+ }
+
+ // 绑定爱心按钮事件(支持触摸)
+ heartBtn.addEventListener('click', toggleToyWheel);
+ heartBtn.addEventListener('touchend', (e) => {
+ e.preventDefault();
+ toggleToyWheel();
+ });
+
+ // 绑定遮罩点击事件(关闭轮盘)
+ overlay.addEventListener('click', closeToyWheel);
+ overlay.addEventListener('touchend', (e) => {
+ e.preventDefault();
+ closeToyWheel();
+ });
+
+ // 绑定轮盘选项事件(支持触摸)
+ wheelOptions.querySelectorAll('.wechat-toy-wheel-option').forEach(opt => {
+ opt.addEventListener('click', (e) => {
+ const index = parseInt(opt.dataset.toyIndex);
+ switchToToy(index);
+ });
+ opt.addEventListener('touchend', (e) => {
+ e.preventDefault();
+ const index = parseInt(opt.dataset.toyIndex);
+ switchToToy(index);
+ });
+ });
+}
+
+// 切换轮盘展开/收起
+function toggleToyWheel() {
+ toyControlState.wheelOpen = !toyControlState.wheelOpen;
+
+ const options = document.querySelector('.wechat-toy-wheel-options');
+ const overlay = document.getElementById('wechat-toy-wheel-overlay');
+ if (options) {
+ options.classList.toggle('open', toyControlState.wheelOpen);
+ }
+ if (overlay) {
+ overlay.classList.toggle('active', toyControlState.wheelOpen);
+ }
+}
+
+// 关闭轮盘
+function closeToyWheel() {
+ toyControlState.wheelOpen = false;
+
+ const options = document.querySelector('.wechat-toy-wheel-options');
+ const overlay = document.getElementById('wechat-toy-wheel-overlay');
+ if (options) {
+ options.classList.remove('open');
+ }
+ if (overlay) {
+ overlay.classList.remove('active');
+ }
+}
+
+// 切换到指定玩具
+async function switchToToy(index) {
+ if (index < 0 || index >= toyControlState.toys.length) return;
+ if (index === toyControlState.currentToyIndex) {
+ // 同一个玩具,只关闭轮盘
+ closeToyWheel();
+ return;
+ }
+
+ const previousToy = toyControlState.toys[toyControlState.currentToyIndex];
+ const newToy = toyControlState.toys[index];
+
+ // 更新当前玩具索引
+ toyControlState.currentToyIndex = index;
+
+ // 更新当前gift信息
+ toyControlState.gift = {
+ ...toyControlState.gift,
+ giftId: newToy.giftId,
+ giftName: newToy.giftName,
+ giftEmoji: newToy.giftEmoji,
+ giftDesc: newToy.giftDesc,
+ hasControl: newToy.hasControl,
+ hasShock: newToy.hasShock
+ };
+
+ // 重置模式状态(切换玩具后从暂停开始)
+ toyControlState.currentMode = null;
+ toyControlState.activeModes.clear();
+
+ // 关闭轮盘状态(渲染时会应用)
+ toyControlState.wheelOpen = false;
+
+ // 重新渲染界面(保留消息)
+ renderToyControlPage();
+
+ // 更新按钮状态
+ document.querySelectorAll('.wechat-toy-btn').forEach(btn => {
+ btn.classList.remove('active');
+ });
+
+ // 添加切换提示消息
+ addToyMessage('system', `已切换到 ${newToy.giftEmoji} ${newToy.giftName}`);
+
+ // AI对切换做出反应
+ showToyTypingIndicator();
+
+ const isCharacterUsing = toyControlState.target === 'character';
+ let prompt;
+
+ if (isCharacterUsing) {
+ prompt = `[玩具切换]
+用户刚把玩具从"${previousToy.giftName}"切换到"${newToy.giftName}"了。
+${newToy.giftName}的特点:${newToy.giftDesc}
+
+请对这个切换做出反应:
+- 可以表现出对新玩具的期待、紧张或好奇
+- 如果是更刺激的玩具可以表现出紧张
+- 如果是比较温和的可以表现出失落或放松
+
+【重要规则】
+1. 只能输出纯文字,禁止使用任何特殊格式标签
+2. 禁止使用小括号描述动作如(xxx)
+3. 回复简短,1-2句话即可`;
+ } else {
+ prompt = `[玩具切换]
+你把用户正在用的玩具从"${previousToy.giftName}"切换到"${newToy.giftName}"了。
+${newToy.giftName}的特点:${newToy.giftDesc}
+
+请对这个切换做出反应:
+- 可以调侃用户接下来要体验的感觉
+- 或者表达你为什么要给用户换这个
+
+【重要规则】
+1. 只能输出纯文字,禁止使用任何特殊格式标签
+2. 禁止使用小括号描述动作如(xxx)
+3. 回复简短,1-2句话即可`;
+ }
+
+ try {
+ const response = await callToyAI(prompt);
+ hideToyTypingIndicator();
+
+ if (response) {
+ let reply = response.trim();
+ reply = reply.replace(/<\s*meme\s*>[\s\S]*?<\s*\/\s*meme\s*>/gi, '').trim();
+ reply = reply.replace(/\[.*?\]/g, '').trim();
+ reply = reply.replace(/([^)]*)/g, '').trim();
+ reply = reply.replace(/\([^)]*\)/g, '').trim();
+
+ if (reply) {
+ addToyMessage('ai', reply);
+ }
+ }
+ } catch (err) {
+ hideToyTypingIndicator();
+ console.error('[可乐] 玩具切换AI回复失败:', err);
+ }
+}
+
// 绑定事件
let toyEventsBound = false;
function bindToyControlEvents() {
@@ -216,6 +493,12 @@ function bindToyControlEvents() {
document.getElementById('wechat-toy-control-buttons')?.addEventListener('click', (e) => {
const btn = e.target.closest('.wechat-toy-btn');
if (btn) {
+ // 检查是否是媒体按钮(麦克风/摄像头)
+ const media = btn.dataset.media;
+ if (media) {
+ onMediaToggle(media);
+ return;
+ }
const mode = btn.dataset.mode;
if (mode) {
onButtonPress(mode, 'user');
@@ -234,6 +517,99 @@ function bindToyControlEvents() {
});
}
+// 麦克风/摄像头切换处理
+async function onMediaToggle(mediaType) {
+ if (!toyControlState.isActive) return;
+
+ const isMic = mediaType === 'mic';
+ const wasEnabled = isMic ? toyControlState.micEnabled : toyControlState.cameraEnabled;
+ const nowEnabled = !wasEnabled;
+
+ // 更新状态
+ if (isMic) {
+ toyControlState.micEnabled = nowEnabled;
+ } else {
+ toyControlState.cameraEnabled = nowEnabled;
+ }
+
+ // 更新按钮图标
+ updateMediaButtonUI();
+
+ // 显示typing
+ showToyTypingIndicator();
+
+ // 构建提示词
+ const prompt = buildMediaTogglePrompt(mediaType, nowEnabled);
+
+ try {
+ const response = await callToyAI(prompt);
+ hideToyTypingIndicator();
+
+ if (response) {
+ await processAIResponse(response);
+ }
+ } catch (err) {
+ hideToyTypingIndicator();
+ console.error('[可乐] 玩具控制AI回复失败:', err);
+ }
+}
+
+// 更新媒体按钮UI
+function updateMediaButtonUI() {
+ const micBtn = document.querySelector('.wechat-toy-btn-media[data-media="mic"]');
+ const cameraBtn = document.querySelector('.wechat-toy-btn-media[data-media="camera"]');
+
+ if (micBtn) {
+ micBtn.innerHTML = toyControlState.micEnabled ? TOY_ICONS.micOn : TOY_ICONS.micOff;
+ micBtn.classList.toggle('active', toyControlState.micEnabled);
+ }
+ if (cameraBtn) {
+ cameraBtn.innerHTML = toyControlState.cameraEnabled ? TOY_ICONS.cameraOn : TOY_ICONS.cameraOff;
+ cameraBtn.classList.toggle('active', toyControlState.cameraEnabled);
+ }
+}
+
+// 构建媒体切换提示词
+function buildMediaTogglePrompt(mediaType, isEnabled) {
+ const isCharacterUsing = toyControlState.target === 'character';
+ const isMic = mediaType === 'mic';
+ const mediaName = isMic ? '麦克风' : '摄像头';
+ const action = isEnabled ? '打开' : '关闭';
+
+ let prompt = `【${mediaName}${action}】\n`;
+
+ if (isCharacterUsing) {
+ // 角色在用玩具
+ if (isEnabled) {
+ prompt += isMic
+ ? `用户打开了麦克风,现在可以听到用户的声音了。你正在使用玩具,听到用户的声音会让你更有感觉。请做出反应。`
+ : `用户打开了摄像头,现在可以看到用户了。你正在使用玩具,看到用户会让你更害羞/更有感觉。请做出反应。`;
+ } else {
+ prompt += isMic
+ ? `用户关闭了麦克风,现在听不到用户的声音了。你可能会有点失落或者松一口气。请做出反应。`
+ : `用户关闭了摄像头,现在看不到用户了。你可能会有点失落或者松一口气。请做出反应。`;
+ }
+ } else {
+ // 用户在用玩具
+ if (isEnabled) {
+ prompt += isMic
+ ? `用户打开了麦克风,你现在可以听到用户的声音/喘息/呻吟了。请做出反应,可以调侃、撩拨或关心用户。`
+ : `用户打开了摄像头,你现在可以看到用户使用玩具的样子了。请做出反应,可以调侃、撩拨或关心用户。`;
+ } else {
+ prompt += isMic
+ ? `用户关闭了麦克风,你现在听不到用户的声音了。请做出反应。`
+ : `用户关闭了摄像头,你现在看不到用户了。请做出反应。`;
+ }
+ }
+
+ prompt += `\n\n【当前状态】
+- 麦克风:${toyControlState.micEnabled ? '已打开(可以听到声音)' : '已关闭'}
+- 摄像头:${toyControlState.cameraEnabled ? '已打开(可以看到画面)' : '已关闭'}
+- 当前模式:${toyControlState.currentMode ? (TOY_CONTROL_MODES[toyControlState.currentMode]?.name || '已暂停') : '未开始'}`;
+
+ return prompt;
+}
+
// 按钮点击处理
async function onButtonPress(buttonId, pressedBy = 'user') {
if (!toyControlState.isActive) return;
@@ -345,6 +721,18 @@ function buildButtonPressPrompt(buttonId, buttonName, pressedBy) {
3. 禁止使用[语音:xxx]、[照片:xxx]、[表情:xxx]等格式
4. 直接输出角色说的话和感受`;
+ // 添加当前媒体状态信息
+ const mediaStatus = [];
+ if (toyControlState.micEnabled) {
+ mediaStatus.push('麦克风已开启(可以听到对方的声音/喘息)');
+ }
+ if (toyControlState.cameraEnabled) {
+ mediaStatus.push('摄像头已开启(可以看到对方)');
+ }
+ if (mediaStatus.length > 0) {
+ prompt += `\n\n【当前连接状态】${mediaStatus.join(',')}`;
+ }
+
return prompt;
}
@@ -644,21 +1032,44 @@ function saveToySession() {
const seconds = (durationSec % 60).toString().padStart(2, '0');
const durationStr = `${minutes}:${seconds}`;
- const session = {
- gift: {
- id: toyControlState.gift.giftId,
- name: toyControlState.gift.giftName,
- emoji: toyControlState.gift.giftEmoji
- },
- target: toyControlState.target,
- time: timeStr,
- timestamp: toyControlState.sessionStartTime || Date.now(),
- duration: durationStr,
- messages: toyControlState.messages.map(m => ({
- role: m.role,
- content: m.content
- }))
- };
+ // 构建session记录
+ let session;
+ if (toyControlState.isMulti) {
+ // 多玩具模式
+ session = {
+ isMulti: true,
+ toys: toyControlState.toys.map(t => ({
+ id: t.giftId,
+ name: t.giftName,
+ emoji: t.giftEmoji
+ })),
+ target: toyControlState.target,
+ time: timeStr,
+ timestamp: toyControlState.sessionStartTime || Date.now(),
+ duration: durationStr,
+ messages: toyControlState.messages.map(m => ({
+ role: m.role,
+ content: m.content
+ }))
+ };
+ } else {
+ // 单玩具模式
+ session = {
+ gift: {
+ id: toyControlState.gift.giftId,
+ name: toyControlState.gift.giftName,
+ emoji: toyControlState.gift.giftEmoji
+ },
+ target: toyControlState.target,
+ time: timeStr,
+ timestamp: toyControlState.sessionStartTime || Date.now(),
+ duration: durationStr,
+ messages: toyControlState.messages.map(m => ({
+ role: m.role,
+ content: m.content
+ }))
+ };
+ }
contact.toyHistory.push(session);