# mumu小手机

## **一个可以对话的小手机**

<figure><img src="https://cdn.mufy.ai/images/885552af-8c0b-4a03-7a40-cd2c3e08db00/public" alt=""><figcaption></figcaption></figure>

实现在对话过程中，使用小手机做为交互形式。

{% hint style="info" %}
原理：

* 将AI输出和用户输入，使用两个字符传入，$1，$2。
* 其中，单条消息采用|||分割
* 使用代码，参照|||分割的原则，实现提取出AI输出，用户输入
* 例如下方例子，可以分割出用户输入“干嘛”、“怎么喂不饱”，AI的输出：“罐头！”、“要吃罐头！”、“多多的罐头！”
* 本案例还使用了一个小脚本，可以实现在小手机中发送消息，同步操控mufy输入框发送
  {% endhint %}

<figure><img src="https://cdn.mufy.ai/images/d1d18834-d3bc-49b9-26b9-b3d9908a6100/public" alt=""><figcaption></figcaption></figure>

#### 目标字符

"使用符号匹配模式"，填写中括号即可

```
<Phone>
    <UserInput>汇总用户在本次对话中发送的所有消息，使用|||分隔每条独立消息</UserInput>
    <AiInput>汇总角色在本次对话中回复的所有消息，使用|||分隔每条独立回复</AiInput>
</Phone>
```

#### 替换字符串

<details>

<summary><mark style="color:$primary;">代码过长，点击展开/收起</mark></summary>

````html
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>暗色金属质感手机界面</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        /* 自定义滚动条隐藏 */
        .no-scrollbar::-webkit-scrollbar { display: none; }
        .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }

        /* 金属拉丝渐变 */
        .metal-finish {
            background: linear-gradient(180deg, #334155 0%, #1e293b 40%, #020617 100%);
        }

        /* 气泡动画 */
        @keyframes popIn {
            from { opacity: 0; transform: scale(0.95) translateY(10px); }
            to { opacity: 1; transform: scale(1) translateY(0); }
        }
        .message-anim { animation: popIn 0.3s ease-out forwards; }

        /* 规则面板动画 */
        .rules-anim {
            transform-origin: top right;
            animation: growIn 0.2s ease-out forwards;
        }
        @keyframes growIn {
            from { opacity: 0; transform: scale(0.9) translateY(-10px); }
            to { opacity: 1; transform: scale(1) translateY(0); }
        }

        /* 禁用状态按钮样式 */
        #submit-btn:disabled {
            background-color: #1e293b;
            border-color: #334155;
            color: #64748b;
            cursor: not-allowed;
            opacity: 0.6;
            box-shadow: none;
            transform: none;
        }
    </style>
</head>
<body class="min-h-screen flex items-center justify-center p-4 font-sans antialiased text-slate-300">

    <div class="relative w-[320px] h-[650px] metal-finish rounded-[44px] shadow-[0_50px_100px_-20px_rgba(0,0,0,1)] p-[8px] flex flex-col border border-white/10">
        <div class="absolute inset-0 rounded-[44px] border-[0.5px] border-white/20 pointer-events-none"></div>

        <div class="flex-1 bg-[#0a0a0b] rounded-[36px] overflow-hidden flex flex-col relative border border-black shadow-[inset_0_0_10px_rgba(0,0,0,0.8)]">
            <div class="absolute top-0 left-1/2 -translate-x-1/2 w-24 h-6 bg-black rounded-b-2xl z-20"></div>
            
            <div class="h-10 px-6 pt-1 flex justify-between items-center text-[11px] font-bold text-zinc-400 z-10">
                <span>14:25</span>
                <div class="flex gap-1.5 items-center">
                    <i class="fas fa-signal"></i><i class="fas fa-wifi"></i>
                    <div class="w-5 h-2.5 border border-zinc-700 rounded-[2px] relative flex items-center px-[1px]">
                        <div class="h-[80%] bg-zinc-300 w-[60%] rounded-[1px]"></div>
                    </div>
                </div>
            </div>

            <div class="h-12 bg-[#0a0a0b]/80 backdrop-blur-md border-b border-white/5 flex items-center justify-between px-4 mt-1 shrink-0 relative">
                <div class="w-8"></div> 
                <h1 class="font-semibold text-[14px] text-zinc-100">MUMU🐱</h1>
                <button onclick="toggleRules()" class="w-8 h-8 flex items-center justify-center text-zinc-400 hover:text-white transition-colors">
                    <i class="fas fa-ellipsis-h text-sm"></i>
                </button>

                <div id="rules-panel" class="absolute top-11 right-4 w-48 bg-zinc-900/95 backdrop-blur-xl border border-white/10 rounded-xl shadow-2xl p-4 z-50 hidden rules-anim">
                    <h4 class="text-[11px] font-bold text-emerald-500 uppercase tracking-wider mb-2">使用规则</h4>
                    <ul class="text-[10px] text-zinc-400 space-y-2 leading-tight">
                        <li class="flex gap-1.5"><span class="text-emerald-500">•</span><span>输入内容按回车预览</span></li>
                        <li class="flex gap-1.5"><span class="text-emerald-500">•</span><span><strong>清空输入框</strong>后方可结束发送</span></li>
                    </ul>
                </div>
            </div>

            <div id="chat-container" onclick="closeRules()" class="flex-1 overflow-y-auto px-4 py-4 space-y-5 no-scrollbar bg-gradient-to-b from-[#0a0a0b] to-[#111113]"></div>

            <div class="px-3 pt-2 pb-8 bg-[#0a0a0b] border-t border-white/5 flex items-center gap-3 shrink-0">
                <div class="flex-1 relative">
                    <input 
                        id="chat-input"
                        type="text" 
                        placeholder="输入内容并回车..."
                        class="w-full h-10 bg-zinc-900/50 text-zinc-200 rounded-xl px-4 text-sm border border-zinc-800/50 outline-none focus:border-emerald-600/50 transition-all placeholder:text-zinc-500"
                    >
                </div>
                <button id="submit-btn" onclick="submitToParent()" class="whitespace-nowrap h-10 bg-emerald-600 hover:bg-emerald-500 text-white px-4 rounded-xl shadow-lg transition-all active:scale-95 text-[12px] font-bold border border-emerald-400/20">
                    结束发送
                </button>
            </div>
            <div class="absolute bottom-1.5 left-1/2 -translate-x-1/2 w-28 h-[4px] bg-zinc-800 rounded-full"></div>
        </div>
    </div>

    <script>
        const chatContainer = document.getElementById('chat-container');
        const chatInput = document.getElementById('chat-input');
        const submitBtn = document.getElementById('submit-btn');
        const rulesPanel = document.getElementById('rules-panel');

        const FRIEND_AVATAR = "https://cdn.mufy.ai/images/9b350667-10e5-43ea-efd8-aac249556d00/public";
        const MY_AVATAR = "https://cdn.mufy.ai/images/b41c873a-449d-4539-56ee-15abbd5bc700/public";

        const userInput = `$1`; 
        const aiInput = `$2`; 
        let newUserMessages = [];

        function scrollToBottom() { chatContainer.scrollTop = chatContainer.scrollHeight; }
        function toggleRules() { rulesPanel.classList.toggle('hidden'); }
        function closeRules() { rulesPanel.classList.add('hidden'); }

        // --- 新增：检查输入框内容以控制按钮状态 ---
        function checkInputStatus() {
            const hasValue = chatInput.value.trim().length > 0;
            submitBtn.disabled = hasValue;
            // 改变按钮视觉反馈（如果是禁用状态，Tailwind 的 hover 会由于 disabled 属性失效）
            if (hasValue) {
                submitBtn.classList.add('opacity-50');
                submitBtn.title = "请先按回车确认当前输入的内容";
            } else {
                submitBtn.classList.remove('opacity-50');
                submitBtn.title = "";
            }
        }

        function createMessageElement(text, isMe, isAnim = true) {
            const wrapper = document.createElement('div');
            wrapper.className = `flex ${isMe ? 'flex-row-reverse' : 'flex-row'} items-start gap-2.5 ${isAnim ? 'message-anim' : ''}`;
            wrapper.innerHTML = `
                <div class="w-9 h-9 rounded-[10px] bg-zinc-800 border border-white/10 shadow-md overflow-hidden shrink-0">
                    <img src="${isMe ? MY_AVATAR : FRIEND_AVATAR}" class="w-full h-full object-cover">
                </div>
                <div class="flex flex-col space-y-1 max-w-[75%]">
                    <div class="relative px-3.5 py-2.5 rounded-2xl text-[13px] leading-[1.4] tracking-wide 
                        ${isMe ? 'bg-[#07c160] text-white rounded-tr-[4px]' : 'bg-zinc-800/80 text-zinc-100 rounded-tl-[4px] border border-white/5'}">
                        ${text}
                    </div>
                </div>
            `;
            return wrapper;
        }

        function initChat() {
            if (userInput && typeof userInput === 'string') {
                userInput.split('|||').forEach(text => {
                    if (text.trim()) chatContainer.appendChild(createMessageElement(text.trim(), true, false));
                });
            }
            if (aiInput && typeof aiInput === 'string') {
                aiInput.split('|||').forEach(text => {
                    if (text.trim()) chatContainer.appendChild(createMessageElement(text.trim(), false, false));
                });
            }
            scrollToBottom();
            checkInputStatus(); // 初始化按钮状态
        }

        function smartFill(text, autoSend) {
                const parentDoc = window.parent.document;
                const textarea = parentDoc.querySelector('textarea.text-blackAlpha-700') || 
                                parentDoc.querySelector('textarea[placeholder*="Enter"]');

                if (!textarea) {
                    console.error("未找到输入框");
                    return;
                }

                const nativeValueSetter = Object.getOwnPropertyDescriptor(
                    window.parent.HTMLTextAreaElement.prototype, 
                    "value"
                ).set;

                nativeValueSetter.call(textarea, text);

                const inputEvent = new Event('input', { bubbles: true });
                textarea.dispatchEvent(inputEvent);
                
                const changeEvent = new Event('change', { bubbles: true });
                textarea.dispatchEvent(changeEvent);

                if (autoSend) {
                    setTimeout(() => {
                        textarea.focus();
                        const sendBtn = textarea.closest('.relative')?.querySelector('button:not([disabled])');
                        
                        if (sendBtn && !sendBtn.disabled) {
                            sendBtn.click();
                        } else {
                            const enterEvent = new KeyboardEvent('keydown', {
                                key: 'Enter',
                                code: 'Enter',
                                keyCode: 13,
                                which: 13,
                                bubbles: true,
                                cancelable: true
                            });
                            textarea.dispatchEvent(enterEvent);
                        }
                    }, 100);
                }
            }


        function addLocalMessage() {
            const text = chatInput.value.trim();
            if (!text) return;
            chatContainer.appendChild(createMessageElement(text, true));
            newUserMessages.push(text);
            chatInput.value = '';
            checkInputStatus(); // 清空后恢复按钮
            scrollToBottom();
        }

        function submitToParent() {
            if (newUserMessages.length === 0) return;
            const finalPayload = newUserMessages.join('|||');
            // 此处调用您的智能填充逻辑...
            console.log("发送到父组件:", finalPayload);
            smartFill(finalPayload, true);
        }

        // 监听输入事件
        chatInput.addEventListener('input', checkInputStatus);

        chatInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') {
                addLocalMessage();
                e.preventDefault();
            }
        });

        window.onload = initChat;
    </script>
</body>
</html>
```
````

</details>

#### 输出设定

```
严格按照以下XML结构输出手机聊天组件，不要输出任何其他内容：

<Phone>
    <UserInput>汇总用户在本次对话中发送的所有消息，使用|||分隔每条独立消息</UserInput>
    <AiInput>汇总角色在本次对话中回复的所有消息，使用|||分隔每条独立回复</AiInput>
</Phone>

【字段说明】
- <UserInput>：完整记录上一条用户发送的全部对话内容，每条消息末尾添加|||符号，最后一条消息无需添加
- <AiInput>：完整记录角色回复的全部对话内容，每条回复末尾添加|||符号，最后一条回复无需添加

【重要约束】
- 仅输出XML结构，禁止添加开场白、解释性文字或多余内容
- 严格保留标签名称<Phone><UserInput><AiInput>，不得修改
- 确保消息内容准确还原对话原文，不进行删减或润色
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mufy.ai/documentation/guan-yu-zheng-ze/you-qu-an-li/mumu-xiao-shou-ji.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
