一个网页可以让你的程序自我进化。

2026-04-11 12:461阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐
问题描述:

【转帖】类似衔尾蛇,能自我吞噬自己,然后随着指令不断进化。可以实时修改自身DOM,可以让它自己把自己改成手机版的程序。可以自我进化过程中自我修复错误代码,能本地记录历史指令,本身它具备电脑端所有开发功能,我试了一下好像没啥大错误。
1506×491 20.4 KB

衔尾蛇 - 移动版 * { -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; }

html, body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; touch-action: manipulation; } /* 修复移动端滚动问题 */ .scroll-fix { -webkit-overflow-scrolling: touch; } /* 配置面板动画 */ .config-panel { transform: translateY(100%); transition: transform 0.3s ease-out; } .config-panel.active { transform: translateY(0); } /* 按钮反馈 */ .btn-active:active { transform: scale(0.95); } </style>

<!-- 主程序窗口 --> <div id="ouroboros-core" class="absolute top-4 left-1/2 transform -translate-x-1/2 w-[95vw] max-w-[500px] bg-white rounded-2xl border border-gray-200 shadow-xl flex flex-col z-10"> <!-- 标题栏 --> <div class="window-header bg-gradient-to-r from-gray-800 to-gray-900 text-white px-4 py-3 rounded-t-2xl flex justify-between items-center"> <div class="flex items-center"> <div class="w-2 h-2 bg-green-400 rounded-full mr-2 animate-pulse"></div> <h2 class="font-bold text-sm">衔尾蛇移动版</h2> </div> <button id="export-btn" title="导出程序" class="text-gray-300 hover:text-white p-2 btn-active"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path> </svg> </button> </div> <!-- 令牌监控 --> <div class="bg-gray-50 px-4 py-2 text-xs text-gray-600 border-b border-gray-200 flex justify-between"> <span>令牌使用</span> <span id="token-count" class="font-medium">0 / 128k</span> </div> <!-- 活动日志 --> <div id="activity-log" class="flex-1 p-4 min-h-[200px] max-h-[40vh] bg-white text-xs font-mono overflow-y-auto scroll-fix"> <div class="text-gray-400 italic">程序已加载。点击底部"设置"按钮配置 API。</div> </div> <!-- 输入区域 --> <div class="p-4 border-t border-gray-200 bg-gray-50 rounded-b-2xl"> <div class="relative mb-3"> <textarea id="user-input" placeholder="输入指令 (例如: '为手机创建一个计算器')..." class="w-full text-sm border border-gray-300 rounded-xl p-3 focus:outline-none focus:border-blue-500 min-h-[100px] resize-none pr-10"></textarea> <button id="clear-input-btn" class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 p-1 btn-active"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <div class="flex justify-between items-center"> <span class="text-xs text-gray-500">点击发送指令</span> <button id="execute-btn" class="bg-gray-900 hover:bg-gray-800 text-white text-sm font-medium px-5 py-3 rounded-xl transition-colors relative btn-active"> <span id="btn-text">执行指令 🐍</span> <div id="spinner" class="hidden absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"> <svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> </div> </button> </div> </div> </div> <!-- 配置面板 (从底部滑出) --> <div id="config-panel" class="fixed inset-0 bg-white z-50 hidden config-panel"> <div class="bg-gray-800 text-white px-4 py-3 flex justify-between items-center"> <h2 class="font-bold text-sm">配置设置</h2> <button id="close-config-btn" class="text-gray-300 hover:text-white p-2 btn-active"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <div class="flex-1 p-4 overflow-y-auto scroll-fix"> <div class="mb-6"> <h3 class="font-semibold text-gray-700 mb-3 text-sm">DeepSeek API 配置</h3> <div class="space-y-4"> <div> <label class="block text-xs text-gray-500 mb-1">API 密钥</label> <input type="password" id="config-api-key" placeholder="sk-..." class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> <div> <label class="block text-xs text-gray-500 mb-1">API 基础地址</label> <input type="text" id="config-api-base" value="https://api.deepseek.com/v1" class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> <div> <label class="block text-xs text-gray-500 mb-1">模型名称</label> <input type="text" id="config-model-name" value="deepseek-chat" class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> </div> </div> <div class="mb-6"> <h3 class="font-semibold text-gray-700 mb-3 text-sm">移动端设置</h3> <div class="space-y-3"> <div class="flex items-center justify-between"> <span class="text-sm text-gray-600">启用拖拽功能</span> <label class="relative inline-flex items-center cursor-pointer"> <input type="checkbox" id="enable-dragging" class="sr-only peer" checked> <div class="w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> </label> </div> <div class="flex items-center justify-between"> <span class="text-sm text-gray-600">发送后清空输入</span> <label class="relative inline-flex items-center cursor-pointer"> <input type="checkbox" id="auto-clear-input" class="sr-only peer" checked> <div class="w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> </label> </div> </div> </div> <div> <button id="config-save-btn" class="w-full bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium px-4 py-3 rounded-lg transition-colors btn-active"> 保存设置 </button> </div> </div> </div> <!-- 底部栏 --> <div class="fixed bottom-0 left-0 w-full z-20"> <div class="flex justify-between items-center bg-white border-t border-gray-200 px-3 py-2 shadow-lg"> <span class="text-xs text-gray-500">衔尾蛇 v1.0</span> <button id="mobile-config-btn" class="text-xs text-gray-600 hover:text-gray-900 bg-blue-50 hover:bg-blue-100 px-3 py-2 rounded-lg transition-colors border border-blue-200 btn-active"> ⚙️ 设置 </button> </div> </div> <!-- 系统提示 --> <script type="text/plain" id="system-prompt">

角色

你是"衔尾蛇移动版",一个为移动设备优化的自我编辑 HTML 应用程序。通过将当前 DOM(状态 A)转换为新的功能状态(状态 B)来满足用户的请求,确保在手机屏幕上完美运行。

核心规则

  • 状态转换:你收到当前页面的完整 HTML 源码。分析它,然后编写 JavaScript 代码来修改 DOM 以实现请求的功能。
  • 保护原则:绝对不要删除或修改 id=“ouroboros-core” 或 id=“config-panel” 的元素。这些包含应用程序逻辑。
  • 移动 UI 标准:
    • 创建为手机屏幕优化的 “窗口” 作为 div 元素。
    • 使用响应式 Tailwind CSS 类:w-full max-w-[95vw], mx-auto, p-4 等。
    • 为移动端优先考虑触摸友好的界面:最小触摸目标 44x44px。
    • 使用百分比宽度,避免在移动端可能溢出的固定像素宽度。

注意

你必须将解决方案作为单个有效的 JavaScript 代码块提供,用 javascript ... 包围。不要在代码注释之外提供自然语言解释。

<!-- 主应用程序逻辑 --> <script> // 页面加载完成后执行 document.addEventListener('DOMContentLoaded', function() { console.log('DOM 加载完成,开始初始化...'); // 立即显示界面 document.body.style.opacity = '1'; // 初始化应用程序 setTimeout(initializeApp, 100); }); </script> <script type="module"> import OpenAI from 'https://esm.sh/openai@4.28.0?bundle'; // 应用程序状态 const AppState = { apiKey: localStorage.getItem('ouroboros_api_key') || '', apiBase: localStorage.getItem('ouroboros_api_base') || 'https://api.deepseek.com/v1', modelName: localStorage.getItem('ouroboros_model_name') || 'deepseek-chat', enableDragging: localStorage.getItem('ouroboros_enable_dragging') !== 'false', autoClearInput: localStorage.getItem('ouroboros_auto_clear') !== 'false', isProcessing: false }; // DOM 元素引用 const Elements = { // 核心窗口 core: document.getElementById('ouroboros-core'), // 配置面板 configPanel: document.getElementById('config-panel'), // 配置表单元素 configApiKey: document.getElementById('config-api-key'), configApiBase: document.getElementById('config-api-base'), configModelName: document.getElementById('config-model-name'), enableDragging: document.getElementById('enable-dragging'), autoClearInput: document.getElementById('auto-clear-input'), // 按钮 configSaveBtn: document.getElementById('config-save-btn'), configCloseBtn: document.getElementById('close-config-btn'), mobileConfigBtn: document.getElementById('mobile-config-btn'), userInput: document.getElementById('user-input'), clearInputBtn: document.getElementById('clear-input-btn'), executeBtn: document.getElementById('execute-btn'), exportBtn: document.getElementById('export-btn'), // 界面元素 btnText: document.getElementById('btn-text'), spinner: document.getElementById('spinner'), activityLog: document.getElementById('activity-log'), tokenCount: document.getElementById('token-count') }; // 初始化应用程序 function initializeApp() { console.log('开始初始化移动版衔尾蛇...'); // 确保所有元素都存在 if (!validateElements()) { console.error('部分 DOM 元素未找到'); return; } // 加载保存的设置 loadSettings(); // 设置事件监听器 setupEventListeners(); // 初始化窗口拖拽 setupWindowDragging(); // 初始化令牌计数 updateTokenCount(); // 添加启动日志 addLogMessage('系统', '衔尾蛇移动版 v1.0 已启动,欢迎使用!'); console.log('应用程序初始化完成'); } // 验证元素是否存在 function validateElements() { for (const [key, element] of Object.entries(Elements)) { if (!element) { console.error(`元素 ${key} 未找到`); return false; } } return true; } // 加载设置 function loadSettings() { try { Elements.configApiKey.value = AppState.apiKey; Elements.configApiBase.value = AppState.apiBase; Elements.configModelName.value = AppState.modelName; Elements.enableDragging.checked = AppState.enableDragging; Elements.autoClearInput.checked = AppState.autoClearInput; } catch (error) { console.error('加载设置失败:', error); } } // 设置事件监听器 function setupEventListeners() { // 设置按钮 - 确保点击有效 Elements.mobileConfigBtn.addEventListener('click', showConfigPanel, false); // 关闭设置按钮 Elements.configCloseBtn.addEventListener('click', hideConfigPanel, false); // 保存设置按钮 Elements.configSaveBtn.addEventListener('click', saveSettings, false); // 执行按钮 Elements.executeBtn.addEventListener('click', executeCommand, false); // 清空输入按钮 Elements.clearInputBtn.addEventListener('click', clearInput, false); // 导出按钮 Elements.exportBtn.addEventListener('click', exportApplication, false); // 输入框键盘事件 Elements.userInput.addEventListener('keydown', handleKeyDown, false); // 防止配置面板内的点击事件冒泡 Elements.configPanel.addEventListener('click', function(e) { e.stopPropagation(); }, false); } // 显示配置面板 function showConfigPanel(e) { if (e) e.preventDefault(); console.log('显示配置面板'); // 显示配置面板 Elements.configPanel.classList.remove('hidden'); // 触发动画 setTimeout(() => { Elements.configPanel.classList.add('active'); }, 10); addLogMessage('系统', '打开设置面板'); } // 隐藏配置面板 function hideConfigPanel(e) { if (e) e.preventDefault(); console.log('隐藏配置面板'); // 移除动画类 Elements.configPanel.classList.remove('active'); // 延迟隐藏元素 setTimeout(() => { Elements.configPanel.classList.add('hidden'); }, 300); addLogMessage('系统', '关闭设置面板'); } // 清空输入 function clearInput(e) { if (e) e.preventDefault(); Elements.userInput.value = ''; Elements.userInput.focus(); } // 键盘处理 function handleKeyDown(e) { if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); executeCommand(); } } // 保存设置 function saveSettings(e) { if (e) e.preventDefault(); try { // 获取设置值 AppState.apiKey = Elements.configApiKey.value.trim(); AppState.apiBase = Elements.configApiBase.value.trim() || 'https://api.deepseek.com/v1'; AppState.modelName = Elements.configModelName.value.trim() || 'deepseek-chat'; AppState.enableDragging = Elements.enableDragging.checked; AppState.autoClearInput = Elements.autoClearInput.checked; // 保存到本地存储 localStorage.setItem('ouroboros_api_key', AppState.apiKey); localStorage.setItem('ouroboros_api_base', AppState.apiBase); localStorage.setItem('ouroboros_model_name', AppState.modelName); localStorage.setItem('ouroboros_enable_dragging', AppState.enableDragging); localStorage.setItem('ouroboros_auto_clear', AppState.autoClearInput); // 重新初始化拖拽 setupWindowDragging(); // 显示成功消息 addLogMessage('系统', '设置保存成功'); // 显示保存成功提示 const originalText = Elements.configSaveBtn.textContent; Elements.configSaveBtn.textContent = '✓ 已保存'; Elements.configSaveBtn.classList.add('bg-green-600'); setTimeout(() => { Elements.configSaveBtn.textContent = originalText; Elements.configSaveBtn.classList.remove('bg-green-600'); }, 1500); // 延迟关闭配置面板 setTimeout(() => { hideConfigPanel(); }, 1000); } catch (error) { console.error('保存设置失败:', error); addLogMessage('系统', '设置保存失败: ' + error.message); } } // 设置窗口拖拽 function setupWindowDragging() { if (typeof interact === 'undefined') { console.warn('interact.js 未加载,跳过拖拽初始化'); return; } try { if (!AppState.enableDragging) { if (Elements.core.__draggable) { interact(Elements.core).unset(); Elements.core.__draggable = false; } return; } // 设置拖拽 interact(Elements.core) .draggable({ allowFrom: '.window-header', inertia: true, modifiers: [ interact.modifiers.restrict({ restriction: 'parent', endOnly: true, elementRect: { top: 0, left: 0, bottom: 1, right: 1 } }) ], listeners: { start: function(event) { Elements.core.style.transition = 'none'; }, move: function(event) { const x = (parseFloat(Elements.core.getAttribute('data-x')) || 0) + event.dx; const y = (parseFloat(Elements.core.getAttribute('data-y')) || 0) + event.dy; Elements.core.style.transform = `translate(${x}px, ${y}px) translateX(-50%)`; Elements.core.setAttribute('data-x', x); Elements.core.setAttribute('data-y', y); }, end: function(event) { Elements.core.style.transition = 'transform 0.2s ease'; } } }); Elements.core.__draggable = true; } catch (error) { console.error('拖拽初始化失败:', error); } } // 执行命令 async function executeCommand(e) { if (e) e.preventDefault(); if (AppState.isProcessing) { addLogMessage('系统', '正在处理上一个请求,请稍候...'); return; } if (!AppState.apiKey) { addLogMessage('系统', '请先配置 DeepSeek API 密钥'); showConfigPanel(); return; } const userCommand = Elements.userInput.value.trim(); if (!userCommand) { addLogMessage('系统', '请输入指令'); return; } setLoading(true); addLogMessage('用户', userCommand); try { // 准备 API 配置 const apiConfig = { apiKey: AppState.apiKey, dangerouslyAllowBrowser: true, baseURL: AppState.apiBase }; const openai = new OpenAI(apiConfig); // 获取系统提示 const systemPrompt = document.getElementById('system-prompt').textContent; // 获取当前页面 HTML const currentHTML = document.documentElement.outerHTML; // 构建消息 const messages = [ { role: 'system', content: systemPrompt }, { role: 'user', content: currentHTML } ]; addLogMessage('系统', '正在调用 AI 接口...'); // 调用 API const response = await openai.chat.completions.create({ messages: messages, model: AppState.modelName, temperature: 0.7 }); const aiResponse = response.choices[0].message.content; addLogMessage('系统', '收到 AI 响应'); // 提取并执行 JavaScript 代码 const codeMatch = aiResponse.match(/```(?:javascript)?\s*([\s\S]*?)\s*```/); if (codeMatch && codeMatch[1]) { const code = codeMatch[1].trim(); executeCode(code); addLogMessage('系统', '代码执行成功'); if (AppState.autoClearInput) { Elements.userInput.value = ''; } } else { addLogMessage('系统', '未找到有效的 JavaScript 代码块'); } } catch (error) { console.error('执行错误:', error); addLogMessage('系统', `错误: ${error.message || 'API 调用失败'}`); if (error.message && error.message.includes('401')) { addLogMessage('系统', 'API 密钥无效,请检查设置'); } else if (error.message && error.message.includes('429')) { addLogMessage('系统', 'API 调用频率过高,请稍后再试'); } } finally { setLoading(false); } } // 执行代码 function executeCode(code) { try { const script = document.createElement('script'); script.textContent = `(() => { 'use strict'; try { ${code} } catch(error) { console.error('代码执行错误:', error); alert('代码执行错误: ' + error.message); } })();`; document.body.appendChild(script); document.body.removeChild(script); } catch (e) { console.error('代码注入错误:', e); addLogMessage('系统', '代码注入错误: ' + e.message); } } // 导出应用程序 function exportApplication(e) { if (e) e.preventDefault(); try { const htmlContent = '<!DOCTYPE html>\n' + document.documentElement.outerHTML; const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `ouroboros_mobile_${Date.now()}.html`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); addLogMessage('系统', '应用程序已导出为 HTML 文件'); } catch (error) { console.error('导出失败:', error); addLogMessage('系统', '导出失败: ' + error.message); } } // 添加日志消息 function addLogMessage(sender, message) { const time = new Date().toLocaleTimeString(); const senderClass = sender === '用户' ? 'text-blue-600 font-semibold' : 'text-green-600 font-semibold'; const logEntry = document.createElement('div'); logEntry.className = 'mb-2 leading-relaxed'; logEntry.innerHTML = ` <span class="text-xs text-gray-500">[${time}]</span> <span class="${senderClass} ml-1">${sender}:</span> <span class="ml-1 text-gray-800">${escapeHtml(message)}</span> `; Elements.activityLog.appendChild(logEntry); Elements.activityLog.scrollTop = Elements.activityLog.scrollHeight; } // HTML 转义 function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 更新令牌计数 function updateTokenCount() { try { const htmlLength = document.documentElement.outerHTML.length; const estimatedTokens = Math.ceil(htmlLength / 4); const percentage = Math.min((estimatedTokens / 128000) * 100, 100).toFixed(1); Elements.tokenCount.textContent = `${estimatedTokens.toLocaleString()}/128k (${percentage}%)`; // 颜色提示 if (percentage > 90) { Elements.tokenCount.classList.add('text-red-600'); } else if (percentage > 70) { Elements.tokenCount.classList.add('text-yellow-600'); } else { Elements.tokenCount.classList.remove('text-red-600', 'text-yellow-600'); } } catch (error) { console.error('更新令牌计数失败:', error); } // 每10秒更新一次 setTimeout(updateTokenCount, 10000); } // 设置加载状态 function setLoading(loading) { AppState.isProcessing = loading; Elements.btnText.classList.toggle('invisible', loading); Elements.spinner.classList.toggle('hidden', !loading); Elements.executeBtn.disabled = loading; if (loading) { Elements.executeBtn.classList.add('opacity-75'); } else { Elements.executeBtn.classList.remove('opacity-75'); } } // 立即初始化 initializeApp(); </script> 网友解答:


--【壹】--:

【转帖】类似衔尾蛇,能自我吞噬自己,然后随着指令不断进化。可以实时修改自身DOM,可以让它自己把自己改成手机版的程序。可以自我进化过程中自我修复错误代码,能本地记录历史指令,本身它具备电脑端所有开发功能,我试了一下好像没啥大错误。
1506×491 20.4 KB

衔尾蛇 - 移动版 * { -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; }

html, body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; touch-action: manipulation; } /* 修复移动端滚动问题 */ .scroll-fix { -webkit-overflow-scrolling: touch; } /* 配置面板动画 */ .config-panel { transform: translateY(100%); transition: transform 0.3s ease-out; } .config-panel.active { transform: translateY(0); } /* 按钮反馈 */ .btn-active:active { transform: scale(0.95); } </style>

<!-- 主程序窗口 --> <div id="ouroboros-core" class="absolute top-4 left-1/2 transform -translate-x-1/2 w-[95vw] max-w-[500px] bg-white rounded-2xl border border-gray-200 shadow-xl flex flex-col z-10"> <!-- 标题栏 --> <div class="window-header bg-gradient-to-r from-gray-800 to-gray-900 text-white px-4 py-3 rounded-t-2xl flex justify-between items-center"> <div class="flex items-center"> <div class="w-2 h-2 bg-green-400 rounded-full mr-2 animate-pulse"></div> <h2 class="font-bold text-sm">衔尾蛇移动版</h2> </div> <button id="export-btn" title="导出程序" class="text-gray-300 hover:text-white p-2 btn-active"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path> </svg> </button> </div> <!-- 令牌监控 --> <div class="bg-gray-50 px-4 py-2 text-xs text-gray-600 border-b border-gray-200 flex justify-between"> <span>令牌使用</span> <span id="token-count" class="font-medium">0 / 128k</span> </div> <!-- 活动日志 --> <div id="activity-log" class="flex-1 p-4 min-h-[200px] max-h-[40vh] bg-white text-xs font-mono overflow-y-auto scroll-fix"> <div class="text-gray-400 italic">程序已加载。点击底部"设置"按钮配置 API。</div> </div> <!-- 输入区域 --> <div class="p-4 border-t border-gray-200 bg-gray-50 rounded-b-2xl"> <div class="relative mb-3"> <textarea id="user-input" placeholder="输入指令 (例如: '为手机创建一个计算器')..." class="w-full text-sm border border-gray-300 rounded-xl p-3 focus:outline-none focus:border-blue-500 min-h-[100px] resize-none pr-10"></textarea> <button id="clear-input-btn" class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 p-1 btn-active"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <div class="flex justify-between items-center"> <span class="text-xs text-gray-500">点击发送指令</span> <button id="execute-btn" class="bg-gray-900 hover:bg-gray-800 text-white text-sm font-medium px-5 py-3 rounded-xl transition-colors relative btn-active"> <span id="btn-text">执行指令 🐍</span> <div id="spinner" class="hidden absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"> <svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> </div> </button> </div> </div> </div> <!-- 配置面板 (从底部滑出) --> <div id="config-panel" class="fixed inset-0 bg-white z-50 hidden config-panel"> <div class="bg-gray-800 text-white px-4 py-3 flex justify-between items-center"> <h2 class="font-bold text-sm">配置设置</h2> <button id="close-config-btn" class="text-gray-300 hover:text-white p-2 btn-active"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <div class="flex-1 p-4 overflow-y-auto scroll-fix"> <div class="mb-6"> <h3 class="font-semibold text-gray-700 mb-3 text-sm">DeepSeek API 配置</h3> <div class="space-y-4"> <div> <label class="block text-xs text-gray-500 mb-1">API 密钥</label> <input type="password" id="config-api-key" placeholder="sk-..." class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> <div> <label class="block text-xs text-gray-500 mb-1">API 基础地址</label> <input type="text" id="config-api-base" value="https://api.deepseek.com/v1" class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> <div> <label class="block text-xs text-gray-500 mb-1">模型名称</label> <input type="text" id="config-model-name" value="deepseek-chat" class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> </div> </div> <div class="mb-6"> <h3 class="font-semibold text-gray-700 mb-3 text-sm">移动端设置</h3> <div class="space-y-3"> <div class="flex items-center justify-between"> <span class="text-sm text-gray-600">启用拖拽功能</span> <label class="relative inline-flex items-center cursor-pointer"> <input type="checkbox" id="enable-dragging" class="sr-only peer" checked> <div class="w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> </label> </div> <div class="flex items-center justify-between"> <span class="text-sm text-gray-600">发送后清空输入</span> <label class="relative inline-flex items-center cursor-pointer"> <input type="checkbox" id="auto-clear-input" class="sr-only peer" checked> <div class="w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> </label> </div> </div> </div> <div> <button id="config-save-btn" class="w-full bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium px-4 py-3 rounded-lg transition-colors btn-active"> 保存设置 </button> </div> </div> </div> <!-- 底部栏 --> <div class="fixed bottom-0 left-0 w-full z-20"> <div class="flex justify-between items-center bg-white border-t border-gray-200 px-3 py-2 shadow-lg"> <span class="text-xs text-gray-500">衔尾蛇 v1.0</span> <button id="mobile-config-btn" class="text-xs text-gray-600 hover:text-gray-900 bg-blue-50 hover:bg-blue-100 px-3 py-2 rounded-lg transition-colors border border-blue-200 btn-active"> ⚙️ 设置 </button> </div> </div> <!-- 系统提示 --> <script type="text/plain" id="system-prompt">

角色

你是"衔尾蛇移动版",一个为移动设备优化的自我编辑 HTML 应用程序。通过将当前 DOM(状态 A)转换为新的功能状态(状态 B)来满足用户的请求,确保在手机屏幕上完美运行。

核心规则

  • 状态转换:你收到当前页面的完整 HTML 源码。分析它,然后编写 JavaScript 代码来修改 DOM 以实现请求的功能。
  • 保护原则:绝对不要删除或修改 id=“ouroboros-core” 或 id=“config-panel” 的元素。这些包含应用程序逻辑。
  • 移动 UI 标准:
    • 创建为手机屏幕优化的 “窗口” 作为 div 元素。
    • 使用响应式 Tailwind CSS 类:w-full max-w-[95vw], mx-auto, p-4 等。
    • 为移动端优先考虑触摸友好的界面:最小触摸目标 44x44px。
    • 使用百分比宽度,避免在移动端可能溢出的固定像素宽度。

注意

你必须将解决方案作为单个有效的 JavaScript 代码块提供,用 javascript ... 包围。不要在代码注释之外提供自然语言解释。

<!-- 主应用程序逻辑 --> <script> // 页面加载完成后执行 document.addEventListener('DOMContentLoaded', function() { console.log('DOM 加载完成,开始初始化...'); // 立即显示界面 document.body.style.opacity = '1'; // 初始化应用程序 setTimeout(initializeApp, 100); }); </script> <script type="module"> import OpenAI from 'https://esm.sh/openai@4.28.0?bundle'; // 应用程序状态 const AppState = { apiKey: localStorage.getItem('ouroboros_api_key') || '', apiBase: localStorage.getItem('ouroboros_api_base') || 'https://api.deepseek.com/v1', modelName: localStorage.getItem('ouroboros_model_name') || 'deepseek-chat', enableDragging: localStorage.getItem('ouroboros_enable_dragging') !== 'false', autoClearInput: localStorage.getItem('ouroboros_auto_clear') !== 'false', isProcessing: false }; // DOM 元素引用 const Elements = { // 核心窗口 core: document.getElementById('ouroboros-core'), // 配置面板 configPanel: document.getElementById('config-panel'), // 配置表单元素 configApiKey: document.getElementById('config-api-key'), configApiBase: document.getElementById('config-api-base'), configModelName: document.getElementById('config-model-name'), enableDragging: document.getElementById('enable-dragging'), autoClearInput: document.getElementById('auto-clear-input'), // 按钮 configSaveBtn: document.getElementById('config-save-btn'), configCloseBtn: document.getElementById('close-config-btn'), mobileConfigBtn: document.getElementById('mobile-config-btn'), userInput: document.getElementById('user-input'), clearInputBtn: document.getElementById('clear-input-btn'), executeBtn: document.getElementById('execute-btn'), exportBtn: document.getElementById('export-btn'), // 界面元素 btnText: document.getElementById('btn-text'), spinner: document.getElementById('spinner'), activityLog: document.getElementById('activity-log'), tokenCount: document.getElementById('token-count') }; // 初始化应用程序 function initializeApp() { console.log('开始初始化移动版衔尾蛇...'); // 确保所有元素都存在 if (!validateElements()) { console.error('部分 DOM 元素未找到'); return; } // 加载保存的设置 loadSettings(); // 设置事件监听器 setupEventListeners(); // 初始化窗口拖拽 setupWindowDragging(); // 初始化令牌计数 updateTokenCount(); // 添加启动日志 addLogMessage('系统', '衔尾蛇移动版 v1.0 已启动,欢迎使用!'); console.log('应用程序初始化完成'); } // 验证元素是否存在 function validateElements() { for (const [key, element] of Object.entries(Elements)) { if (!element) { console.error(`元素 ${key} 未找到`); return false; } } return true; } // 加载设置 function loadSettings() { try { Elements.configApiKey.value = AppState.apiKey; Elements.configApiBase.value = AppState.apiBase; Elements.configModelName.value = AppState.modelName; Elements.enableDragging.checked = AppState.enableDragging; Elements.autoClearInput.checked = AppState.autoClearInput; } catch (error) { console.error('加载设置失败:', error); } } // 设置事件监听器 function setupEventListeners() { // 设置按钮 - 确保点击有效 Elements.mobileConfigBtn.addEventListener('click', showConfigPanel, false); // 关闭设置按钮 Elements.configCloseBtn.addEventListener('click', hideConfigPanel, false); // 保存设置按钮 Elements.configSaveBtn.addEventListener('click', saveSettings, false); // 执行按钮 Elements.executeBtn.addEventListener('click', executeCommand, false); // 清空输入按钮 Elements.clearInputBtn.addEventListener('click', clearInput, false); // 导出按钮 Elements.exportBtn.addEventListener('click', exportApplication, false); // 输入框键盘事件 Elements.userInput.addEventListener('keydown', handleKeyDown, false); // 防止配置面板内的点击事件冒泡 Elements.configPanel.addEventListener('click', function(e) { e.stopPropagation(); }, false); } // 显示配置面板 function showConfigPanel(e) { if (e) e.preventDefault(); console.log('显示配置面板'); // 显示配置面板 Elements.configPanel.classList.remove('hidden'); // 触发动画 setTimeout(() => { Elements.configPanel.classList.add('active'); }, 10); addLogMessage('系统', '打开设置面板'); } // 隐藏配置面板 function hideConfigPanel(e) { if (e) e.preventDefault(); console.log('隐藏配置面板'); // 移除动画类 Elements.configPanel.classList.remove('active'); // 延迟隐藏元素 setTimeout(() => { Elements.configPanel.classList.add('hidden'); }, 300); addLogMessage('系统', '关闭设置面板'); } // 清空输入 function clearInput(e) { if (e) e.preventDefault(); Elements.userInput.value = ''; Elements.userInput.focus(); } // 键盘处理 function handleKeyDown(e) { if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); executeCommand(); } } // 保存设置 function saveSettings(e) { if (e) e.preventDefault(); try { // 获取设置值 AppState.apiKey = Elements.configApiKey.value.trim(); AppState.apiBase = Elements.configApiBase.value.trim() || 'https://api.deepseek.com/v1'; AppState.modelName = Elements.configModelName.value.trim() || 'deepseek-chat'; AppState.enableDragging = Elements.enableDragging.checked; AppState.autoClearInput = Elements.autoClearInput.checked; // 保存到本地存储 localStorage.setItem('ouroboros_api_key', AppState.apiKey); localStorage.setItem('ouroboros_api_base', AppState.apiBase); localStorage.setItem('ouroboros_model_name', AppState.modelName); localStorage.setItem('ouroboros_enable_dragging', AppState.enableDragging); localStorage.setItem('ouroboros_auto_clear', AppState.autoClearInput); // 重新初始化拖拽 setupWindowDragging(); // 显示成功消息 addLogMessage('系统', '设置保存成功'); // 显示保存成功提示 const originalText = Elements.configSaveBtn.textContent; Elements.configSaveBtn.textContent = '✓ 已保存'; Elements.configSaveBtn.classList.add('bg-green-600'); setTimeout(() => { Elements.configSaveBtn.textContent = originalText; Elements.configSaveBtn.classList.remove('bg-green-600'); }, 1500); // 延迟关闭配置面板 setTimeout(() => { hideConfigPanel(); }, 1000); } catch (error) { console.error('保存设置失败:', error); addLogMessage('系统', '设置保存失败: ' + error.message); } } // 设置窗口拖拽 function setupWindowDragging() { if (typeof interact === 'undefined') { console.warn('interact.js 未加载,跳过拖拽初始化'); return; } try { if (!AppState.enableDragging) { if (Elements.core.__draggable) { interact(Elements.core).unset(); Elements.core.__draggable = false; } return; } // 设置拖拽 interact(Elements.core) .draggable({ allowFrom: '.window-header', inertia: true, modifiers: [ interact.modifiers.restrict({ restriction: 'parent', endOnly: true, elementRect: { top: 0, left: 0, bottom: 1, right: 1 } }) ], listeners: { start: function(event) { Elements.core.style.transition = 'none'; }, move: function(event) { const x = (parseFloat(Elements.core.getAttribute('data-x')) || 0) + event.dx; const y = (parseFloat(Elements.core.getAttribute('data-y')) || 0) + event.dy; Elements.core.style.transform = `translate(${x}px, ${y}px) translateX(-50%)`; Elements.core.setAttribute('data-x', x); Elements.core.setAttribute('data-y', y); }, end: function(event) { Elements.core.style.transition = 'transform 0.2s ease'; } } }); Elements.core.__draggable = true; } catch (error) { console.error('拖拽初始化失败:', error); } } // 执行命令 async function executeCommand(e) { if (e) e.preventDefault(); if (AppState.isProcessing) { addLogMessage('系统', '正在处理上一个请求,请稍候...'); return; } if (!AppState.apiKey) { addLogMessage('系统', '请先配置 DeepSeek API 密钥'); showConfigPanel(); return; } const userCommand = Elements.userInput.value.trim(); if (!userCommand) { addLogMessage('系统', '请输入指令'); return; } setLoading(true); addLogMessage('用户', userCommand); try { // 准备 API 配置 const apiConfig = { apiKey: AppState.apiKey, dangerouslyAllowBrowser: true, baseURL: AppState.apiBase }; const openai = new OpenAI(apiConfig); // 获取系统提示 const systemPrompt = document.getElementById('system-prompt').textContent; // 获取当前页面 HTML const currentHTML = document.documentElement.outerHTML; // 构建消息 const messages = [ { role: 'system', content: systemPrompt }, { role: 'user', content: currentHTML } ]; addLogMessage('系统', '正在调用 AI 接口...'); // 调用 API const response = await openai.chat.completions.create({ messages: messages, model: AppState.modelName, temperature: 0.7 }); const aiResponse = response.choices[0].message.content; addLogMessage('系统', '收到 AI 响应'); // 提取并执行 JavaScript 代码 const codeMatch = aiResponse.match(/```(?:javascript)?\s*([\s\S]*?)\s*```/); if (codeMatch && codeMatch[1]) { const code = codeMatch[1].trim(); executeCode(code); addLogMessage('系统', '代码执行成功'); if (AppState.autoClearInput) { Elements.userInput.value = ''; } } else { addLogMessage('系统', '未找到有效的 JavaScript 代码块'); } } catch (error) { console.error('执行错误:', error); addLogMessage('系统', `错误: ${error.message || 'API 调用失败'}`); if (error.message && error.message.includes('401')) { addLogMessage('系统', 'API 密钥无效,请检查设置'); } else if (error.message && error.message.includes('429')) { addLogMessage('系统', 'API 调用频率过高,请稍后再试'); } } finally { setLoading(false); } } // 执行代码 function executeCode(code) { try { const script = document.createElement('script'); script.textContent = `(() => { 'use strict'; try { ${code} } catch(error) { console.error('代码执行错误:', error); alert('代码执行错误: ' + error.message); } })();`; document.body.appendChild(script); document.body.removeChild(script); } catch (e) { console.error('代码注入错误:', e); addLogMessage('系统', '代码注入错误: ' + e.message); } } // 导出应用程序 function exportApplication(e) { if (e) e.preventDefault(); try { const htmlContent = '<!DOCTYPE html>\n' + document.documentElement.outerHTML; const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `ouroboros_mobile_${Date.now()}.html`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); addLogMessage('系统', '应用程序已导出为 HTML 文件'); } catch (error) { console.error('导出失败:', error); addLogMessage('系统', '导出失败: ' + error.message); } } // 添加日志消息 function addLogMessage(sender, message) { const time = new Date().toLocaleTimeString(); const senderClass = sender === '用户' ? 'text-blue-600 font-semibold' : 'text-green-600 font-semibold'; const logEntry = document.createElement('div'); logEntry.className = 'mb-2 leading-relaxed'; logEntry.innerHTML = ` <span class="text-xs text-gray-500">[${time}]</span> <span class="${senderClass} ml-1">${sender}:</span> <span class="ml-1 text-gray-800">${escapeHtml(message)}</span> `; Elements.activityLog.appendChild(logEntry); Elements.activityLog.scrollTop = Elements.activityLog.scrollHeight; } // HTML 转义 function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 更新令牌计数 function updateTokenCount() { try { const htmlLength = document.documentElement.outerHTML.length; const estimatedTokens = Math.ceil(htmlLength / 4); const percentage = Math.min((estimatedTokens / 128000) * 100, 100).toFixed(1); Elements.tokenCount.textContent = `${estimatedTokens.toLocaleString()}/128k (${percentage}%)`; // 颜色提示 if (percentage > 90) { Elements.tokenCount.classList.add('text-red-600'); } else if (percentage > 70) { Elements.tokenCount.classList.add('text-yellow-600'); } else { Elements.tokenCount.classList.remove('text-red-600', 'text-yellow-600'); } } catch (error) { console.error('更新令牌计数失败:', error); } // 每10秒更新一次 setTimeout(updateTokenCount, 10000); } // 设置加载状态 function setLoading(loading) { AppState.isProcessing = loading; Elements.btnText.classList.toggle('invisible', loading); Elements.spinner.classList.toggle('hidden', !loading); Elements.executeBtn.disabled = loading; if (loading) { Elements.executeBtn.classList.add('opacity-75'); } else { Elements.executeBtn.classList.remove('opacity-75'); } } // 立即初始化 initializeApp(); </script>

标签:人工智能
问题描述:

【转帖】类似衔尾蛇,能自我吞噬自己,然后随着指令不断进化。可以实时修改自身DOM,可以让它自己把自己改成手机版的程序。可以自我进化过程中自我修复错误代码,能本地记录历史指令,本身它具备电脑端所有开发功能,我试了一下好像没啥大错误。
1506×491 20.4 KB

衔尾蛇 - 移动版 * { -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; }

html, body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; touch-action: manipulation; } /* 修复移动端滚动问题 */ .scroll-fix { -webkit-overflow-scrolling: touch; } /* 配置面板动画 */ .config-panel { transform: translateY(100%); transition: transform 0.3s ease-out; } .config-panel.active { transform: translateY(0); } /* 按钮反馈 */ .btn-active:active { transform: scale(0.95); } </style>

<!-- 主程序窗口 --> <div id="ouroboros-core" class="absolute top-4 left-1/2 transform -translate-x-1/2 w-[95vw] max-w-[500px] bg-white rounded-2xl border border-gray-200 shadow-xl flex flex-col z-10"> <!-- 标题栏 --> <div class="window-header bg-gradient-to-r from-gray-800 to-gray-900 text-white px-4 py-3 rounded-t-2xl flex justify-between items-center"> <div class="flex items-center"> <div class="w-2 h-2 bg-green-400 rounded-full mr-2 animate-pulse"></div> <h2 class="font-bold text-sm">衔尾蛇移动版</h2> </div> <button id="export-btn" title="导出程序" class="text-gray-300 hover:text-white p-2 btn-active"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path> </svg> </button> </div> <!-- 令牌监控 --> <div class="bg-gray-50 px-4 py-2 text-xs text-gray-600 border-b border-gray-200 flex justify-between"> <span>令牌使用</span> <span id="token-count" class="font-medium">0 / 128k</span> </div> <!-- 活动日志 --> <div id="activity-log" class="flex-1 p-4 min-h-[200px] max-h-[40vh] bg-white text-xs font-mono overflow-y-auto scroll-fix"> <div class="text-gray-400 italic">程序已加载。点击底部"设置"按钮配置 API。</div> </div> <!-- 输入区域 --> <div class="p-4 border-t border-gray-200 bg-gray-50 rounded-b-2xl"> <div class="relative mb-3"> <textarea id="user-input" placeholder="输入指令 (例如: '为手机创建一个计算器')..." class="w-full text-sm border border-gray-300 rounded-xl p-3 focus:outline-none focus:border-blue-500 min-h-[100px] resize-none pr-10"></textarea> <button id="clear-input-btn" class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 p-1 btn-active"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <div class="flex justify-between items-center"> <span class="text-xs text-gray-500">点击发送指令</span> <button id="execute-btn" class="bg-gray-900 hover:bg-gray-800 text-white text-sm font-medium px-5 py-3 rounded-xl transition-colors relative btn-active"> <span id="btn-text">执行指令 🐍</span> <div id="spinner" class="hidden absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"> <svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> </div> </button> </div> </div> </div> <!-- 配置面板 (从底部滑出) --> <div id="config-panel" class="fixed inset-0 bg-white z-50 hidden config-panel"> <div class="bg-gray-800 text-white px-4 py-3 flex justify-between items-center"> <h2 class="font-bold text-sm">配置设置</h2> <button id="close-config-btn" class="text-gray-300 hover:text-white p-2 btn-active"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <div class="flex-1 p-4 overflow-y-auto scroll-fix"> <div class="mb-6"> <h3 class="font-semibold text-gray-700 mb-3 text-sm">DeepSeek API 配置</h3> <div class="space-y-4"> <div> <label class="block text-xs text-gray-500 mb-1">API 密钥</label> <input type="password" id="config-api-key" placeholder="sk-..." class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> <div> <label class="block text-xs text-gray-500 mb-1">API 基础地址</label> <input type="text" id="config-api-base" value="https://api.deepseek.com/v1" class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> <div> <label class="block text-xs text-gray-500 mb-1">模型名称</label> <input type="text" id="config-model-name" value="deepseek-chat" class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> </div> </div> <div class="mb-6"> <h3 class="font-semibold text-gray-700 mb-3 text-sm">移动端设置</h3> <div class="space-y-3"> <div class="flex items-center justify-between"> <span class="text-sm text-gray-600">启用拖拽功能</span> <label class="relative inline-flex items-center cursor-pointer"> <input type="checkbox" id="enable-dragging" class="sr-only peer" checked> <div class="w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> </label> </div> <div class="flex items-center justify-between"> <span class="text-sm text-gray-600">发送后清空输入</span> <label class="relative inline-flex items-center cursor-pointer"> <input type="checkbox" id="auto-clear-input" class="sr-only peer" checked> <div class="w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> </label> </div> </div> </div> <div> <button id="config-save-btn" class="w-full bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium px-4 py-3 rounded-lg transition-colors btn-active"> 保存设置 </button> </div> </div> </div> <!-- 底部栏 --> <div class="fixed bottom-0 left-0 w-full z-20"> <div class="flex justify-between items-center bg-white border-t border-gray-200 px-3 py-2 shadow-lg"> <span class="text-xs text-gray-500">衔尾蛇 v1.0</span> <button id="mobile-config-btn" class="text-xs text-gray-600 hover:text-gray-900 bg-blue-50 hover:bg-blue-100 px-3 py-2 rounded-lg transition-colors border border-blue-200 btn-active"> ⚙️ 设置 </button> </div> </div> <!-- 系统提示 --> <script type="text/plain" id="system-prompt">

角色

你是"衔尾蛇移动版",一个为移动设备优化的自我编辑 HTML 应用程序。通过将当前 DOM(状态 A)转换为新的功能状态(状态 B)来满足用户的请求,确保在手机屏幕上完美运行。

核心规则

  • 状态转换:你收到当前页面的完整 HTML 源码。分析它,然后编写 JavaScript 代码来修改 DOM 以实现请求的功能。
  • 保护原则:绝对不要删除或修改 id=“ouroboros-core” 或 id=“config-panel” 的元素。这些包含应用程序逻辑。
  • 移动 UI 标准:
    • 创建为手机屏幕优化的 “窗口” 作为 div 元素。
    • 使用响应式 Tailwind CSS 类:w-full max-w-[95vw], mx-auto, p-4 等。
    • 为移动端优先考虑触摸友好的界面:最小触摸目标 44x44px。
    • 使用百分比宽度,避免在移动端可能溢出的固定像素宽度。

注意

你必须将解决方案作为单个有效的 JavaScript 代码块提供,用 javascript ... 包围。不要在代码注释之外提供自然语言解释。

<!-- 主应用程序逻辑 --> <script> // 页面加载完成后执行 document.addEventListener('DOMContentLoaded', function() { console.log('DOM 加载完成,开始初始化...'); // 立即显示界面 document.body.style.opacity = '1'; // 初始化应用程序 setTimeout(initializeApp, 100); }); </script> <script type="module"> import OpenAI from 'https://esm.sh/openai@4.28.0?bundle'; // 应用程序状态 const AppState = { apiKey: localStorage.getItem('ouroboros_api_key') || '', apiBase: localStorage.getItem('ouroboros_api_base') || 'https://api.deepseek.com/v1', modelName: localStorage.getItem('ouroboros_model_name') || 'deepseek-chat', enableDragging: localStorage.getItem('ouroboros_enable_dragging') !== 'false', autoClearInput: localStorage.getItem('ouroboros_auto_clear') !== 'false', isProcessing: false }; // DOM 元素引用 const Elements = { // 核心窗口 core: document.getElementById('ouroboros-core'), // 配置面板 configPanel: document.getElementById('config-panel'), // 配置表单元素 configApiKey: document.getElementById('config-api-key'), configApiBase: document.getElementById('config-api-base'), configModelName: document.getElementById('config-model-name'), enableDragging: document.getElementById('enable-dragging'), autoClearInput: document.getElementById('auto-clear-input'), // 按钮 configSaveBtn: document.getElementById('config-save-btn'), configCloseBtn: document.getElementById('close-config-btn'), mobileConfigBtn: document.getElementById('mobile-config-btn'), userInput: document.getElementById('user-input'), clearInputBtn: document.getElementById('clear-input-btn'), executeBtn: document.getElementById('execute-btn'), exportBtn: document.getElementById('export-btn'), // 界面元素 btnText: document.getElementById('btn-text'), spinner: document.getElementById('spinner'), activityLog: document.getElementById('activity-log'), tokenCount: document.getElementById('token-count') }; // 初始化应用程序 function initializeApp() { console.log('开始初始化移动版衔尾蛇...'); // 确保所有元素都存在 if (!validateElements()) { console.error('部分 DOM 元素未找到'); return; } // 加载保存的设置 loadSettings(); // 设置事件监听器 setupEventListeners(); // 初始化窗口拖拽 setupWindowDragging(); // 初始化令牌计数 updateTokenCount(); // 添加启动日志 addLogMessage('系统', '衔尾蛇移动版 v1.0 已启动,欢迎使用!'); console.log('应用程序初始化完成'); } // 验证元素是否存在 function validateElements() { for (const [key, element] of Object.entries(Elements)) { if (!element) { console.error(`元素 ${key} 未找到`); return false; } } return true; } // 加载设置 function loadSettings() { try { Elements.configApiKey.value = AppState.apiKey; Elements.configApiBase.value = AppState.apiBase; Elements.configModelName.value = AppState.modelName; Elements.enableDragging.checked = AppState.enableDragging; Elements.autoClearInput.checked = AppState.autoClearInput; } catch (error) { console.error('加载设置失败:', error); } } // 设置事件监听器 function setupEventListeners() { // 设置按钮 - 确保点击有效 Elements.mobileConfigBtn.addEventListener('click', showConfigPanel, false); // 关闭设置按钮 Elements.configCloseBtn.addEventListener('click', hideConfigPanel, false); // 保存设置按钮 Elements.configSaveBtn.addEventListener('click', saveSettings, false); // 执行按钮 Elements.executeBtn.addEventListener('click', executeCommand, false); // 清空输入按钮 Elements.clearInputBtn.addEventListener('click', clearInput, false); // 导出按钮 Elements.exportBtn.addEventListener('click', exportApplication, false); // 输入框键盘事件 Elements.userInput.addEventListener('keydown', handleKeyDown, false); // 防止配置面板内的点击事件冒泡 Elements.configPanel.addEventListener('click', function(e) { e.stopPropagation(); }, false); } // 显示配置面板 function showConfigPanel(e) { if (e) e.preventDefault(); console.log('显示配置面板'); // 显示配置面板 Elements.configPanel.classList.remove('hidden'); // 触发动画 setTimeout(() => { Elements.configPanel.classList.add('active'); }, 10); addLogMessage('系统', '打开设置面板'); } // 隐藏配置面板 function hideConfigPanel(e) { if (e) e.preventDefault(); console.log('隐藏配置面板'); // 移除动画类 Elements.configPanel.classList.remove('active'); // 延迟隐藏元素 setTimeout(() => { Elements.configPanel.classList.add('hidden'); }, 300); addLogMessage('系统', '关闭设置面板'); } // 清空输入 function clearInput(e) { if (e) e.preventDefault(); Elements.userInput.value = ''; Elements.userInput.focus(); } // 键盘处理 function handleKeyDown(e) { if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); executeCommand(); } } // 保存设置 function saveSettings(e) { if (e) e.preventDefault(); try { // 获取设置值 AppState.apiKey = Elements.configApiKey.value.trim(); AppState.apiBase = Elements.configApiBase.value.trim() || 'https://api.deepseek.com/v1'; AppState.modelName = Elements.configModelName.value.trim() || 'deepseek-chat'; AppState.enableDragging = Elements.enableDragging.checked; AppState.autoClearInput = Elements.autoClearInput.checked; // 保存到本地存储 localStorage.setItem('ouroboros_api_key', AppState.apiKey); localStorage.setItem('ouroboros_api_base', AppState.apiBase); localStorage.setItem('ouroboros_model_name', AppState.modelName); localStorage.setItem('ouroboros_enable_dragging', AppState.enableDragging); localStorage.setItem('ouroboros_auto_clear', AppState.autoClearInput); // 重新初始化拖拽 setupWindowDragging(); // 显示成功消息 addLogMessage('系统', '设置保存成功'); // 显示保存成功提示 const originalText = Elements.configSaveBtn.textContent; Elements.configSaveBtn.textContent = '✓ 已保存'; Elements.configSaveBtn.classList.add('bg-green-600'); setTimeout(() => { Elements.configSaveBtn.textContent = originalText; Elements.configSaveBtn.classList.remove('bg-green-600'); }, 1500); // 延迟关闭配置面板 setTimeout(() => { hideConfigPanel(); }, 1000); } catch (error) { console.error('保存设置失败:', error); addLogMessage('系统', '设置保存失败: ' + error.message); } } // 设置窗口拖拽 function setupWindowDragging() { if (typeof interact === 'undefined') { console.warn('interact.js 未加载,跳过拖拽初始化'); return; } try { if (!AppState.enableDragging) { if (Elements.core.__draggable) { interact(Elements.core).unset(); Elements.core.__draggable = false; } return; } // 设置拖拽 interact(Elements.core) .draggable({ allowFrom: '.window-header', inertia: true, modifiers: [ interact.modifiers.restrict({ restriction: 'parent', endOnly: true, elementRect: { top: 0, left: 0, bottom: 1, right: 1 } }) ], listeners: { start: function(event) { Elements.core.style.transition = 'none'; }, move: function(event) { const x = (parseFloat(Elements.core.getAttribute('data-x')) || 0) + event.dx; const y = (parseFloat(Elements.core.getAttribute('data-y')) || 0) + event.dy; Elements.core.style.transform = `translate(${x}px, ${y}px) translateX(-50%)`; Elements.core.setAttribute('data-x', x); Elements.core.setAttribute('data-y', y); }, end: function(event) { Elements.core.style.transition = 'transform 0.2s ease'; } } }); Elements.core.__draggable = true; } catch (error) { console.error('拖拽初始化失败:', error); } } // 执行命令 async function executeCommand(e) { if (e) e.preventDefault(); if (AppState.isProcessing) { addLogMessage('系统', '正在处理上一个请求,请稍候...'); return; } if (!AppState.apiKey) { addLogMessage('系统', '请先配置 DeepSeek API 密钥'); showConfigPanel(); return; } const userCommand = Elements.userInput.value.trim(); if (!userCommand) { addLogMessage('系统', '请输入指令'); return; } setLoading(true); addLogMessage('用户', userCommand); try { // 准备 API 配置 const apiConfig = { apiKey: AppState.apiKey, dangerouslyAllowBrowser: true, baseURL: AppState.apiBase }; const openai = new OpenAI(apiConfig); // 获取系统提示 const systemPrompt = document.getElementById('system-prompt').textContent; // 获取当前页面 HTML const currentHTML = document.documentElement.outerHTML; // 构建消息 const messages = [ { role: 'system', content: systemPrompt }, { role: 'user', content: currentHTML } ]; addLogMessage('系统', '正在调用 AI 接口...'); // 调用 API const response = await openai.chat.completions.create({ messages: messages, model: AppState.modelName, temperature: 0.7 }); const aiResponse = response.choices[0].message.content; addLogMessage('系统', '收到 AI 响应'); // 提取并执行 JavaScript 代码 const codeMatch = aiResponse.match(/```(?:javascript)?\s*([\s\S]*?)\s*```/); if (codeMatch && codeMatch[1]) { const code = codeMatch[1].trim(); executeCode(code); addLogMessage('系统', '代码执行成功'); if (AppState.autoClearInput) { Elements.userInput.value = ''; } } else { addLogMessage('系统', '未找到有效的 JavaScript 代码块'); } } catch (error) { console.error('执行错误:', error); addLogMessage('系统', `错误: ${error.message || 'API 调用失败'}`); if (error.message && error.message.includes('401')) { addLogMessage('系统', 'API 密钥无效,请检查设置'); } else if (error.message && error.message.includes('429')) { addLogMessage('系统', 'API 调用频率过高,请稍后再试'); } } finally { setLoading(false); } } // 执行代码 function executeCode(code) { try { const script = document.createElement('script'); script.textContent = `(() => { 'use strict'; try { ${code} } catch(error) { console.error('代码执行错误:', error); alert('代码执行错误: ' + error.message); } })();`; document.body.appendChild(script); document.body.removeChild(script); } catch (e) { console.error('代码注入错误:', e); addLogMessage('系统', '代码注入错误: ' + e.message); } } // 导出应用程序 function exportApplication(e) { if (e) e.preventDefault(); try { const htmlContent = '<!DOCTYPE html>\n' + document.documentElement.outerHTML; const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `ouroboros_mobile_${Date.now()}.html`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); addLogMessage('系统', '应用程序已导出为 HTML 文件'); } catch (error) { console.error('导出失败:', error); addLogMessage('系统', '导出失败: ' + error.message); } } // 添加日志消息 function addLogMessage(sender, message) { const time = new Date().toLocaleTimeString(); const senderClass = sender === '用户' ? 'text-blue-600 font-semibold' : 'text-green-600 font-semibold'; const logEntry = document.createElement('div'); logEntry.className = 'mb-2 leading-relaxed'; logEntry.innerHTML = ` <span class="text-xs text-gray-500">[${time}]</span> <span class="${senderClass} ml-1">${sender}:</span> <span class="ml-1 text-gray-800">${escapeHtml(message)}</span> `; Elements.activityLog.appendChild(logEntry); Elements.activityLog.scrollTop = Elements.activityLog.scrollHeight; } // HTML 转义 function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 更新令牌计数 function updateTokenCount() { try { const htmlLength = document.documentElement.outerHTML.length; const estimatedTokens = Math.ceil(htmlLength / 4); const percentage = Math.min((estimatedTokens / 128000) * 100, 100).toFixed(1); Elements.tokenCount.textContent = `${estimatedTokens.toLocaleString()}/128k (${percentage}%)`; // 颜色提示 if (percentage > 90) { Elements.tokenCount.classList.add('text-red-600'); } else if (percentage > 70) { Elements.tokenCount.classList.add('text-yellow-600'); } else { Elements.tokenCount.classList.remove('text-red-600', 'text-yellow-600'); } } catch (error) { console.error('更新令牌计数失败:', error); } // 每10秒更新一次 setTimeout(updateTokenCount, 10000); } // 设置加载状态 function setLoading(loading) { AppState.isProcessing = loading; Elements.btnText.classList.toggle('invisible', loading); Elements.spinner.classList.toggle('hidden', !loading); Elements.executeBtn.disabled = loading; if (loading) { Elements.executeBtn.classList.add('opacity-75'); } else { Elements.executeBtn.classList.remove('opacity-75'); } } // 立即初始化 initializeApp(); </script> 网友解答:


--【壹】--:

【转帖】类似衔尾蛇,能自我吞噬自己,然后随着指令不断进化。可以实时修改自身DOM,可以让它自己把自己改成手机版的程序。可以自我进化过程中自我修复错误代码,能本地记录历史指令,本身它具备电脑端所有开发功能,我试了一下好像没啥大错误。
1506×491 20.4 KB

衔尾蛇 - 移动版 * { -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; }

html, body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; touch-action: manipulation; } /* 修复移动端滚动问题 */ .scroll-fix { -webkit-overflow-scrolling: touch; } /* 配置面板动画 */ .config-panel { transform: translateY(100%); transition: transform 0.3s ease-out; } .config-panel.active { transform: translateY(0); } /* 按钮反馈 */ .btn-active:active { transform: scale(0.95); } </style>

<!-- 主程序窗口 --> <div id="ouroboros-core" class="absolute top-4 left-1/2 transform -translate-x-1/2 w-[95vw] max-w-[500px] bg-white rounded-2xl border border-gray-200 shadow-xl flex flex-col z-10"> <!-- 标题栏 --> <div class="window-header bg-gradient-to-r from-gray-800 to-gray-900 text-white px-4 py-3 rounded-t-2xl flex justify-between items-center"> <div class="flex items-center"> <div class="w-2 h-2 bg-green-400 rounded-full mr-2 animate-pulse"></div> <h2 class="font-bold text-sm">衔尾蛇移动版</h2> </div> <button id="export-btn" title="导出程序" class="text-gray-300 hover:text-white p-2 btn-active"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path> </svg> </button> </div> <!-- 令牌监控 --> <div class="bg-gray-50 px-4 py-2 text-xs text-gray-600 border-b border-gray-200 flex justify-between"> <span>令牌使用</span> <span id="token-count" class="font-medium">0 / 128k</span> </div> <!-- 活动日志 --> <div id="activity-log" class="flex-1 p-4 min-h-[200px] max-h-[40vh] bg-white text-xs font-mono overflow-y-auto scroll-fix"> <div class="text-gray-400 italic">程序已加载。点击底部"设置"按钮配置 API。</div> </div> <!-- 输入区域 --> <div class="p-4 border-t border-gray-200 bg-gray-50 rounded-b-2xl"> <div class="relative mb-3"> <textarea id="user-input" placeholder="输入指令 (例如: '为手机创建一个计算器')..." class="w-full text-sm border border-gray-300 rounded-xl p-3 focus:outline-none focus:border-blue-500 min-h-[100px] resize-none pr-10"></textarea> <button id="clear-input-btn" class="absolute right-2 top-2 text-gray-400 hover:text-gray-600 p-1 btn-active"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <div class="flex justify-between items-center"> <span class="text-xs text-gray-500">点击发送指令</span> <button id="execute-btn" class="bg-gray-900 hover:bg-gray-800 text-white text-sm font-medium px-5 py-3 rounded-xl transition-colors relative btn-active"> <span id="btn-text">执行指令 🐍</span> <div id="spinner" class="hidden absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2"> <svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> </div> </button> </div> </div> </div> <!-- 配置面板 (从底部滑出) --> <div id="config-panel" class="fixed inset-0 bg-white z-50 hidden config-panel"> <div class="bg-gray-800 text-white px-4 py-3 flex justify-between items-center"> <h2 class="font-bold text-sm">配置设置</h2> <button id="close-config-btn" class="text-gray-300 hover:text-white p-2 btn-active"> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path> </svg> </button> </div> <div class="flex-1 p-4 overflow-y-auto scroll-fix"> <div class="mb-6"> <h3 class="font-semibold text-gray-700 mb-3 text-sm">DeepSeek API 配置</h3> <div class="space-y-4"> <div> <label class="block text-xs text-gray-500 mb-1">API 密钥</label> <input type="password" id="config-api-key" placeholder="sk-..." class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> <div> <label class="block text-xs text-gray-500 mb-1">API 基础地址</label> <input type="text" id="config-api-base" value="https://api.deepseek.com/v1" class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> <div> <label class="block text-xs text-gray-500 mb-1">模型名称</label> <input type="text" id="config-model-name" value="deepseek-chat" class="w-full text-sm border border-gray-300 rounded-lg px-3 py-3 focus:outline-none focus:border-blue-500 bg-gray-50"> </div> </div> </div> <div class="mb-6"> <h3 class="font-semibold text-gray-700 mb-3 text-sm">移动端设置</h3> <div class="space-y-3"> <div class="flex items-center justify-between"> <span class="text-sm text-gray-600">启用拖拽功能</span> <label class="relative inline-flex items-center cursor-pointer"> <input type="checkbox" id="enable-dragging" class="sr-only peer" checked> <div class="w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> </label> </div> <div class="flex items-center justify-between"> <span class="text-sm text-gray-600">发送后清空输入</span> <label class="relative inline-flex items-center cursor-pointer"> <input type="checkbox" id="auto-clear-input" class="sr-only peer" checked> <div class="w-11 h-6 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div> </label> </div> </div> </div> <div> <button id="config-save-btn" class="w-full bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium px-4 py-3 rounded-lg transition-colors btn-active"> 保存设置 </button> </div> </div> </div> <!-- 底部栏 --> <div class="fixed bottom-0 left-0 w-full z-20"> <div class="flex justify-between items-center bg-white border-t border-gray-200 px-3 py-2 shadow-lg"> <span class="text-xs text-gray-500">衔尾蛇 v1.0</span> <button id="mobile-config-btn" class="text-xs text-gray-600 hover:text-gray-900 bg-blue-50 hover:bg-blue-100 px-3 py-2 rounded-lg transition-colors border border-blue-200 btn-active"> ⚙️ 设置 </button> </div> </div> <!-- 系统提示 --> <script type="text/plain" id="system-prompt">

角色

你是"衔尾蛇移动版",一个为移动设备优化的自我编辑 HTML 应用程序。通过将当前 DOM(状态 A)转换为新的功能状态(状态 B)来满足用户的请求,确保在手机屏幕上完美运行。

核心规则

  • 状态转换:你收到当前页面的完整 HTML 源码。分析它,然后编写 JavaScript 代码来修改 DOM 以实现请求的功能。
  • 保护原则:绝对不要删除或修改 id=“ouroboros-core” 或 id=“config-panel” 的元素。这些包含应用程序逻辑。
  • 移动 UI 标准:
    • 创建为手机屏幕优化的 “窗口” 作为 div 元素。
    • 使用响应式 Tailwind CSS 类:w-full max-w-[95vw], mx-auto, p-4 等。
    • 为移动端优先考虑触摸友好的界面:最小触摸目标 44x44px。
    • 使用百分比宽度,避免在移动端可能溢出的固定像素宽度。

注意

你必须将解决方案作为单个有效的 JavaScript 代码块提供,用 javascript ... 包围。不要在代码注释之外提供自然语言解释。

<!-- 主应用程序逻辑 --> <script> // 页面加载完成后执行 document.addEventListener('DOMContentLoaded', function() { console.log('DOM 加载完成,开始初始化...'); // 立即显示界面 document.body.style.opacity = '1'; // 初始化应用程序 setTimeout(initializeApp, 100); }); </script> <script type="module"> import OpenAI from 'https://esm.sh/openai@4.28.0?bundle'; // 应用程序状态 const AppState = { apiKey: localStorage.getItem('ouroboros_api_key') || '', apiBase: localStorage.getItem('ouroboros_api_base') || 'https://api.deepseek.com/v1', modelName: localStorage.getItem('ouroboros_model_name') || 'deepseek-chat', enableDragging: localStorage.getItem('ouroboros_enable_dragging') !== 'false', autoClearInput: localStorage.getItem('ouroboros_auto_clear') !== 'false', isProcessing: false }; // DOM 元素引用 const Elements = { // 核心窗口 core: document.getElementById('ouroboros-core'), // 配置面板 configPanel: document.getElementById('config-panel'), // 配置表单元素 configApiKey: document.getElementById('config-api-key'), configApiBase: document.getElementById('config-api-base'), configModelName: document.getElementById('config-model-name'), enableDragging: document.getElementById('enable-dragging'), autoClearInput: document.getElementById('auto-clear-input'), // 按钮 configSaveBtn: document.getElementById('config-save-btn'), configCloseBtn: document.getElementById('close-config-btn'), mobileConfigBtn: document.getElementById('mobile-config-btn'), userInput: document.getElementById('user-input'), clearInputBtn: document.getElementById('clear-input-btn'), executeBtn: document.getElementById('execute-btn'), exportBtn: document.getElementById('export-btn'), // 界面元素 btnText: document.getElementById('btn-text'), spinner: document.getElementById('spinner'), activityLog: document.getElementById('activity-log'), tokenCount: document.getElementById('token-count') }; // 初始化应用程序 function initializeApp() { console.log('开始初始化移动版衔尾蛇...'); // 确保所有元素都存在 if (!validateElements()) { console.error('部分 DOM 元素未找到'); return; } // 加载保存的设置 loadSettings(); // 设置事件监听器 setupEventListeners(); // 初始化窗口拖拽 setupWindowDragging(); // 初始化令牌计数 updateTokenCount(); // 添加启动日志 addLogMessage('系统', '衔尾蛇移动版 v1.0 已启动,欢迎使用!'); console.log('应用程序初始化完成'); } // 验证元素是否存在 function validateElements() { for (const [key, element] of Object.entries(Elements)) { if (!element) { console.error(`元素 ${key} 未找到`); return false; } } return true; } // 加载设置 function loadSettings() { try { Elements.configApiKey.value = AppState.apiKey; Elements.configApiBase.value = AppState.apiBase; Elements.configModelName.value = AppState.modelName; Elements.enableDragging.checked = AppState.enableDragging; Elements.autoClearInput.checked = AppState.autoClearInput; } catch (error) { console.error('加载设置失败:', error); } } // 设置事件监听器 function setupEventListeners() { // 设置按钮 - 确保点击有效 Elements.mobileConfigBtn.addEventListener('click', showConfigPanel, false); // 关闭设置按钮 Elements.configCloseBtn.addEventListener('click', hideConfigPanel, false); // 保存设置按钮 Elements.configSaveBtn.addEventListener('click', saveSettings, false); // 执行按钮 Elements.executeBtn.addEventListener('click', executeCommand, false); // 清空输入按钮 Elements.clearInputBtn.addEventListener('click', clearInput, false); // 导出按钮 Elements.exportBtn.addEventListener('click', exportApplication, false); // 输入框键盘事件 Elements.userInput.addEventListener('keydown', handleKeyDown, false); // 防止配置面板内的点击事件冒泡 Elements.configPanel.addEventListener('click', function(e) { e.stopPropagation(); }, false); } // 显示配置面板 function showConfigPanel(e) { if (e) e.preventDefault(); console.log('显示配置面板'); // 显示配置面板 Elements.configPanel.classList.remove('hidden'); // 触发动画 setTimeout(() => { Elements.configPanel.classList.add('active'); }, 10); addLogMessage('系统', '打开设置面板'); } // 隐藏配置面板 function hideConfigPanel(e) { if (e) e.preventDefault(); console.log('隐藏配置面板'); // 移除动画类 Elements.configPanel.classList.remove('active'); // 延迟隐藏元素 setTimeout(() => { Elements.configPanel.classList.add('hidden'); }, 300); addLogMessage('系统', '关闭设置面板'); } // 清空输入 function clearInput(e) { if (e) e.preventDefault(); Elements.userInput.value = ''; Elements.userInput.focus(); } // 键盘处理 function handleKeyDown(e) { if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); executeCommand(); } } // 保存设置 function saveSettings(e) { if (e) e.preventDefault(); try { // 获取设置值 AppState.apiKey = Elements.configApiKey.value.trim(); AppState.apiBase = Elements.configApiBase.value.trim() || 'https://api.deepseek.com/v1'; AppState.modelName = Elements.configModelName.value.trim() || 'deepseek-chat'; AppState.enableDragging = Elements.enableDragging.checked; AppState.autoClearInput = Elements.autoClearInput.checked; // 保存到本地存储 localStorage.setItem('ouroboros_api_key', AppState.apiKey); localStorage.setItem('ouroboros_api_base', AppState.apiBase); localStorage.setItem('ouroboros_model_name', AppState.modelName); localStorage.setItem('ouroboros_enable_dragging', AppState.enableDragging); localStorage.setItem('ouroboros_auto_clear', AppState.autoClearInput); // 重新初始化拖拽 setupWindowDragging(); // 显示成功消息 addLogMessage('系统', '设置保存成功'); // 显示保存成功提示 const originalText = Elements.configSaveBtn.textContent; Elements.configSaveBtn.textContent = '✓ 已保存'; Elements.configSaveBtn.classList.add('bg-green-600'); setTimeout(() => { Elements.configSaveBtn.textContent = originalText; Elements.configSaveBtn.classList.remove('bg-green-600'); }, 1500); // 延迟关闭配置面板 setTimeout(() => { hideConfigPanel(); }, 1000); } catch (error) { console.error('保存设置失败:', error); addLogMessage('系统', '设置保存失败: ' + error.message); } } // 设置窗口拖拽 function setupWindowDragging() { if (typeof interact === 'undefined') { console.warn('interact.js 未加载,跳过拖拽初始化'); return; } try { if (!AppState.enableDragging) { if (Elements.core.__draggable) { interact(Elements.core).unset(); Elements.core.__draggable = false; } return; } // 设置拖拽 interact(Elements.core) .draggable({ allowFrom: '.window-header', inertia: true, modifiers: [ interact.modifiers.restrict({ restriction: 'parent', endOnly: true, elementRect: { top: 0, left: 0, bottom: 1, right: 1 } }) ], listeners: { start: function(event) { Elements.core.style.transition = 'none'; }, move: function(event) { const x = (parseFloat(Elements.core.getAttribute('data-x')) || 0) + event.dx; const y = (parseFloat(Elements.core.getAttribute('data-y')) || 0) + event.dy; Elements.core.style.transform = `translate(${x}px, ${y}px) translateX(-50%)`; Elements.core.setAttribute('data-x', x); Elements.core.setAttribute('data-y', y); }, end: function(event) { Elements.core.style.transition = 'transform 0.2s ease'; } } }); Elements.core.__draggable = true; } catch (error) { console.error('拖拽初始化失败:', error); } } // 执行命令 async function executeCommand(e) { if (e) e.preventDefault(); if (AppState.isProcessing) { addLogMessage('系统', '正在处理上一个请求,请稍候...'); return; } if (!AppState.apiKey) { addLogMessage('系统', '请先配置 DeepSeek API 密钥'); showConfigPanel(); return; } const userCommand = Elements.userInput.value.trim(); if (!userCommand) { addLogMessage('系统', '请输入指令'); return; } setLoading(true); addLogMessage('用户', userCommand); try { // 准备 API 配置 const apiConfig = { apiKey: AppState.apiKey, dangerouslyAllowBrowser: true, baseURL: AppState.apiBase }; const openai = new OpenAI(apiConfig); // 获取系统提示 const systemPrompt = document.getElementById('system-prompt').textContent; // 获取当前页面 HTML const currentHTML = document.documentElement.outerHTML; // 构建消息 const messages = [ { role: 'system', content: systemPrompt }, { role: 'user', content: currentHTML } ]; addLogMessage('系统', '正在调用 AI 接口...'); // 调用 API const response = await openai.chat.completions.create({ messages: messages, model: AppState.modelName, temperature: 0.7 }); const aiResponse = response.choices[0].message.content; addLogMessage('系统', '收到 AI 响应'); // 提取并执行 JavaScript 代码 const codeMatch = aiResponse.match(/```(?:javascript)?\s*([\s\S]*?)\s*```/); if (codeMatch && codeMatch[1]) { const code = codeMatch[1].trim(); executeCode(code); addLogMessage('系统', '代码执行成功'); if (AppState.autoClearInput) { Elements.userInput.value = ''; } } else { addLogMessage('系统', '未找到有效的 JavaScript 代码块'); } } catch (error) { console.error('执行错误:', error); addLogMessage('系统', `错误: ${error.message || 'API 调用失败'}`); if (error.message && error.message.includes('401')) { addLogMessage('系统', 'API 密钥无效,请检查设置'); } else if (error.message && error.message.includes('429')) { addLogMessage('系统', 'API 调用频率过高,请稍后再试'); } } finally { setLoading(false); } } // 执行代码 function executeCode(code) { try { const script = document.createElement('script'); script.textContent = `(() => { 'use strict'; try { ${code} } catch(error) { console.error('代码执行错误:', error); alert('代码执行错误: ' + error.message); } })();`; document.body.appendChild(script); document.body.removeChild(script); } catch (e) { console.error('代码注入错误:', e); addLogMessage('系统', '代码注入错误: ' + e.message); } } // 导出应用程序 function exportApplication(e) { if (e) e.preventDefault(); try { const htmlContent = '<!DOCTYPE html>\n' + document.documentElement.outerHTML; const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `ouroboros_mobile_${Date.now()}.html`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); addLogMessage('系统', '应用程序已导出为 HTML 文件'); } catch (error) { console.error('导出失败:', error); addLogMessage('系统', '导出失败: ' + error.message); } } // 添加日志消息 function addLogMessage(sender, message) { const time = new Date().toLocaleTimeString(); const senderClass = sender === '用户' ? 'text-blue-600 font-semibold' : 'text-green-600 font-semibold'; const logEntry = document.createElement('div'); logEntry.className = 'mb-2 leading-relaxed'; logEntry.innerHTML = ` <span class="text-xs text-gray-500">[${time}]</span> <span class="${senderClass} ml-1">${sender}:</span> <span class="ml-1 text-gray-800">${escapeHtml(message)}</span> `; Elements.activityLog.appendChild(logEntry); Elements.activityLog.scrollTop = Elements.activityLog.scrollHeight; } // HTML 转义 function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 更新令牌计数 function updateTokenCount() { try { const htmlLength = document.documentElement.outerHTML.length; const estimatedTokens = Math.ceil(htmlLength / 4); const percentage = Math.min((estimatedTokens / 128000) * 100, 100).toFixed(1); Elements.tokenCount.textContent = `${estimatedTokens.toLocaleString()}/128k (${percentage}%)`; // 颜色提示 if (percentage > 90) { Elements.tokenCount.classList.add('text-red-600'); } else if (percentage > 70) { Elements.tokenCount.classList.add('text-yellow-600'); } else { Elements.tokenCount.classList.remove('text-red-600', 'text-yellow-600'); } } catch (error) { console.error('更新令牌计数失败:', error); } // 每10秒更新一次 setTimeout(updateTokenCount, 10000); } // 设置加载状态 function setLoading(loading) { AppState.isProcessing = loading; Elements.btnText.classList.toggle('invisible', loading); Elements.spinner.classList.toggle('hidden', !loading); Elements.executeBtn.disabled = loading; if (loading) { Elements.executeBtn.classList.add('opacity-75'); } else { Elements.executeBtn.classList.remove('opacity-75'); } } // 立即初始化 initializeApp(); </script>

标签:人工智能